4

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
3
  • Is the last line supposed to stay jkl? May 24, 2011 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”? May 24, 2011 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. May 24, 2011 at 22:29

4 Answers 4

3

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

6
  • 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. May 24, 2011 at 5:52
  • I am getting a syntax error "bad flag in substitute command: '}'" on a Mac running 10.6.7? 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. 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) May 24, 2011 at 14:01
  • 1
    The use of \n in replacement text and the absence of a command separator before } are not standard. May 24, 2011 at 19:23
3

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.

2
  • 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, 2015 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. Oct 30, 2015 at 23:14
2

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
7
  • This also produces a syntax errror, even if I attempt to put it on one line. 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 to sh for my script writing needs. Thanks for the frank feedback. 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. May 24, 2011 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, 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. Oct 30, 2015 at 20:09
1
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 '')" \
    -en\;bn

% 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.

3
  • 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. Oct 30, 2015 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, 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
    Oct 30, 2015 at 19:38

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .