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
  • Is the last line supposed to stay jkl? – Michael Mrozek May 24 '11 at 5:41
  • I don't understand the requirements either. What is 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”? – Gilles 'SO- stop being evil' May 24 '11 at 19:30
  • Oppss. Sorry, I have corrected the example. ALL lines (except the first blank line), stay as they are.. The first blank line gets replaced with %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. – Peter Grill May 24 '11 at 22:29

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 May 24 '11 at 5:52
  • I am getting a syntax error "bad flag in substitute command: '}'" on a Mac running 10.6.7? – Peter Grill May 24 '11 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 May 24 '11 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 May 24 '11 at 14:01
  • 1
    The use of \n in replacement text and the absence of a command separator before } are not standard. – Gilles 'SO- stop being evil' May 24 '11 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 can sed - though very few of us can do it at your level so don't stop doing the sed stuff either - but there's a whole lot less talk about ed around here than i think is due. some of this stuff which can be done with sed just doesn't make a whole lot of sense without ed-style multiple alternate buffers or j and similar. – mikeserv Oct 30 '15 at 23:00
  • 1
    @mikeserv - thanks ! re: ed, you're right... in my quest to improve my sed-fu I've left ed aside for a while. This is all sed'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 some ed solutions to my existing sed/awk posts. And yes, I'll do more ed in the future, I promise. – don_crissti Oct 30 '15 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\

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 May 24 '11 at 6:45
  • I have seen quite a few posts about giving up on csh and after your comment I will switch to sh for my script writing needs. Thanks for the frank feedback. – Peter Grill May 24 '11 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 May 24 '11 at 18:24
  • this inserts the string for every blank line in the file. and if you're using insert anyway, why not just change? – mikeserv Oct 30 '15 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 Oct 30 '15 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

    • inserts the fixed-string to standard out right now
  • a

    • schedules the fixed-string for an append to stdout in the order of scripted occurrence before the next line-cycle, or, for the last line, at the end of this one
  • c

    • deletes the pattern space for all of address[es] (1(,2)?)?, ends the current line-cycle, and changes output to the fixed-string for the last of any address[es]

printf '\n\n\n\n\n' |
sed -e1\!b -e:n \
    -e"/^$/c$(printf '\\\n%%%s' \ ghi '')" \

% ghi

So this script branches out of the script for every line which is ! not the 1st, but from the first line until it can change a blank line to the fixed-string, it auto-prints every not-blank line before overwriting it with the next and looping back to the :next 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 Oct 30 '15 at 19:18
  • @PeterGrill - I don't think it should ever do that. It should only ever change the first occurrence of a blank line, I think... – mikeserv Oct 30 '15 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 Oct 30 '15 at 19:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.