Insert newline before each line matching a pattern unless the previous line is already empty

You could store the previous line in the hold space:

sed '
 /^pattern/{
   x
   /./ {
     x
     s/^/\
/
     x
   }
   x
 }
 h'

It would be more legible with awk though:

awk '!previous_empty && /pattern/ {print ""}
     {previous_empty = $0 == ""; print}'

Like the GNU implementations of sed has a -i option for in-place editing, the GNU implementation of awk as -i inplace for that.


But how do I determine the previous line, of a matching pattern, in the first place?

Umm... perhaps this will work.

Using grep and the -B switch:

 -B num, --before-context=num
         Print num lines of leading context before each match.  See
         also the -A and -C options.

Consider this infile:

cat infile 
foo

bar
baz

Now, if I grep for bar, the previous line should be empty:

if [[ $(grep -B 1 'bar' infile | head -1) == "" ]]; then echo "line is empty"; fi
line is empty

As opposed to using grep on baz, where the previous line is not empty:

if [[ $(grep -B 1 'baz' infile | head -1) == "" ]]; then echo "line is empty"; fi
<no output>

Another way with sed:

sed -e 'tD' -e '$!N;/.\npattern/s/\n/&&/;:D' -e 'P;D' infile

This was explained in detail here: it's basically an N;P;D cycle where we account for the newlines we edit in, so each time the script inserts a \newline it executes only P and D without N so as to always have only two lines in the pattern space.