How do I replace the first blank line with two lines of content? I did see a question on replacing multiple blank lines with a single blank line in vim sed but don't quite see how to adapt that. So, for example, if my input file is:
% abd
% def
% jkl
% mno
I would like to have a sed command that replaces just the first blank line with these two lines (one containing ghi
and the other containing %
):
% abd
% def
% ghi
%
% jkl
% mno
4 Answers 4
Sed matches entire lines but doesn't include the newline, so a blank line will just be an empty string. You can use ^
to match the beginning of a line and $
to match the end, so ^$
matches a blank line. Just replace that with % ghi\n%
:
sed 's/^$/% ghi\n%/'
The newline that already existed will remain, so you'll end up with % ghi
on one line and %
on the next
Edit: If it needs to only match once then the expression is a bit more complicated. The easiest way I know to do it in sed
is:
sed '0,/^$/ s/^$/% ghi\n%/'
The replacement is wrapped in an address range 0,/^$/
, which means "only apply the following to the lines between 0 and the first line that matches ^$
". Since the replacement expression checks for ^$
as well, the only line that's actually going to change is the first that matches ^$
-- the first blank line
-
That works great, but I forgot to mention that i ONLY want it to replace the first blank line. I should be able to add "1" somewhere at the end , bu everywhere I try I seem to get an error.Peter Grill– Peter Grill2011年05月24日 05:52:15 +00:00Commented May 24, 2011 at 5:52
-
I am getting a syntax error "bad flag in substitute command: '}'" on a Mac running 10.6.7?Peter Grill– Peter Grill2011年05月24日 06:16:40 +00:00Commented May 24, 2011 at 6:16
-
If I know the line number, which I do, I can then use the following: s/^$/% ghi\\\n%/' Only problem left is that that \n shows up two characters "\" and "n" near the end of the line as opposed to inserting a carriage return.Peter Grill– Peter Grill2011年05月24日 06:44:01 +00:00Commented May 24, 2011 at 6:44
-
@Peter Is the mac version of sed different? I don't really know anything about macs. If you know the line number this is way easier though:
sed '3 i ghi'
(to insert ghi above line 3)Michael Mrozek– Michael Mrozek2011年05月24日 14:01:29 +00:00Commented May 24, 2011 at 14:01 -
1The use of
\n
in replacement text and the absence of a command separator before}
are not standard.Gilles 'SO- stop being evil'– Gilles 'SO- stop being evil'2011年05月24日 19:23:38 +00:00Commented May 24, 2011 at 19:23
Here's another way with sed
that replaces only the first empty line without using \n
in the RHS or the gnu sed
0 address extension:
sed '/^$/{ # if line is empty
x # exchange pattern space w. hold space
//{ # if pattern space is empty (means the hold buffer was empty)
s//%/ # replace it with a % character
h # overwrite hold space (so now hold space looks like this: ^%$)
s/$/ ghi/ # add a space and the string ghi after the %, then
G # append content of hold buffer to pattern space so now the
} # pattern space looks like this: ^% ghi\n%$
//!x # if pattern space is not empty it means a change was
} # already made so exchange back (do nothing)
' infile
one liner:
sed -e'/^$/{x;//{s//%/;h;s/$/ ghi/;G' -e'}' -e'//!x' -e'}' infile
Though really, this is piece of cake for ed
:
ed -s infile <<< $'/^$/s//% ghi\\\n%/\n,p\nq'
replace ,p
with w
to edit the file in-place.
-
i wish you'd do more of these with
ed
. a lot of us cansed
- though very few of us can do it at your level so don't stop doing thesed
stuff either - but there's a whole lot less talk abouted
around here than i think is due. some of this stuff which can be done withsed
just doesn't make a whole lot of sense withouted
-style multiple alternate buffers orj
and similar.mikeserv– mikeserv2015年10月30日 23:00:04 +00:00Commented Oct 30, 2015 at 23:00 -
1@mikeserv - thanks ! re:
ed
, you're right... in my quest to improve mysed
-fu I've lefted
aside for a while. This is allsed
's fault :) as it can easily get addictive if you know what I mean... Anyway, next month I'll review all my posts here and I'll probably add someed
solutions to my existing sed/awk posts. And yes, I'll do moreed
in the future, I promise.don_crissti– don_crissti2015年10月30日 23:14:35 +00:00Commented Oct 30, 2015 at 23:14
NB: This answers the original question, which asked for:
How do I replace a single blank line with two lines of content?
This does not answer the 'chameleon' question.
sed '/^$/{i\
% ghi\
%
d
}'
When sed
finds a blank line, this inserts the two lines '% ghi
' and '%
', then deletes the blank line.
From the comments
This produces a syntax error.
Use a real shell instead of a sea-shell; it will save everyone grief in the long run. Place the commands on 5 lines of a simple file and use sed -f sed.script
. There are probably other ways to achieve this in C shell - this works, though:
echo '/^$/{\' > sed.script
echo '% ghi\' >> sed.script
echo '%' >> sed.script
echo 'd' >> sed.script
echo '}' >> sed.script
sed -f sed.script data.file
rm -f sed.script
-
This also produces a syntax errror, even if I attempt to put it on one line.Peter Grill– Peter Grill2011年05月24日 06:45:31 +00:00Commented May 24, 2011 at 6:45
-
I have seen quite a few posts about giving up on
csh
and after your comment I will switch tosh
for my script writing needs. Thanks for the frank feedback.Peter Grill– Peter Grill2011年05月24日 18:21:07 +00:00Commented May 24, 2011 at 18:21 -
1@Peter: the definitive demolition of C shell for programming is Csh Programming Considered Harmful. I think you just made a correct decision.Jonathan Leffler– Jonathan Leffler2011年05月24日 18:24:48 +00:00Commented May 24, 2011 at 18:24
-
this inserts the string for every blank line in the file. and if you're using
i
nsert anyway, why not justc
hange?mikeserv– mikeserv2015年10月30日 20:03:46 +00:00Commented Oct 30, 2015 at 20:03 -
2@mikeserv: the question was changed dramatically a long time (multiple hours) after I last edited this answer. Chameleon questions leave valid answers for the original question looking invalid for the revised question.Jonathan Leffler– Jonathan Leffler2015年10月30日 20:09:03 +00:00Commented Oct 30, 2015 at 20:09
sed -e1\!b -e:n -e"/^$/c$(printf '\\\n%%%s' \ ghi '')" -en\;bn
sed
understands three primitives for scripted, fixed-string writes to stdout. All three begin after the immediately following, backslash-escaped newline in the script and end either at the first occurring unescaped newline in the script or the first occurring end-of-file in the script:
i
i
nserts the fixed-string to standard out right now
a
- schedules the fixed-string for an
a
ppend to stdout in the order of scripted occurrence before the next line-cycle, or, for the last line, at the end of this one
- schedules the fixed-string for an
c
- deletes the pattern space for all of address[es]
(1(,2)?)?
, ends the current line-cycle, andc
hanges output to the fixed-string for the last of any address[es]
- deletes the pattern space for all of address[es]
printf '\n\n\n\n\n' |
sed -e1\!b -e:n \
-e"/^$/c$(printf '\\\n%%%s' \ ghi '')" \
-en\;bn
% ghi %
So this script b
ranches out of the script for every line which is !
not the 1
st, but from the first line until it can c
hange a blank line to the fixed-string, it auto-prints every not-blank line before overwriting it with the n
ext and looping back to the :n
ext label to go again.
-
This does the correct thing for the first blank line, but also inserts two lines at the end of the file where I had a blank line as well:
% ghi
and%
. I ONLY want the first occurrence to be replaced.Peter Grill– Peter Grill2015年10月30日 19:18:35 +00:00Commented Oct 30, 2015 at 19:18 -
@PeterGrill - I don't think it should ever do that. It should only ever
c
hange the first occurrence of a blank line, I think...mikeserv– mikeserv2015年10月30日 19:36:36 +00:00Commented Oct 30, 2015 at 19:36 -
@PeterGrill - was the last line the first occurring blank line in the file? if so, then yes, it should do that, because it is supposed only to replace the first occurring blank line.mikeserv– mikeserv2015年10月30日 19:38:51 +00:00Commented Oct 30, 2015 at 19:38
jkl
?jkl
supposed to become? Could you express the requirements in English as well, for example "replace all blank lines by a fixed multi-line text" or "replace all blank lines by a blank line preceded by a copy of the next line"?%ghi\n%
where the\n
represents a linefeed to get me to the next line so that there is a line with just a%
on it. Hope that removes the confusion.