Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sed: delete previous line

Tags:

regex

sed

I need to remove a blank line prior to a match.

So given the file:

random text
more random text






#matchee

I need to match the pattern /#matchee/, then delete the blank line before it.

Here's what I've tried --- no success:

sed '/^[ \t]*$/{N;/#matchee.*$/{D;}}' file.txt

My logic:

  • If blank line; append next line to pattern space yielding /blank line\n...etc/
  • If pattern space contains /#matchee/, Delete up to newline yielding /#matchee/

Basically /matchee/ is a constant that must be maintained and I need to remove an extra blank line from each record in a file of records delimited by /#matchee/.

This produces no effect whatever. I am RTFM-ing and D is supposed to delete pattern space up to the newline. Since N appends a newline plus next line --- this should produce the desired results ....alas ....no and no again. Is this because the match contains essentially nothing ( blankline )?

like image 434
Bubnoff Avatar asked Mar 09 '12 21:03

Bubnoff


1 Answers

Your approach will work if there are an odd number of blank lines, but it will fail if there are an even number. Your sed script is a loop of the following.

  • grab a line L1, and add it to the pattern space
  • if L1 is non-blank, print it; but if it is blank, then:
    • grab another line, L2, and add it to the pattern space
    • if L2 contains #matchee, discard L1 from the pattern space
    • print the pattern space, which is consists either of L1 and L2, or just of L2

You'll notice that L2 is always printed, even if it's blank and followed by a line that contains #matchee. It's protected by the fact that it immediately follows an odd number of blank lines.

Edited to add: To fix the above-described problem, you can add an inner loop by using the : command to create a label and the b command to "branch" to it (goto). This:

sed '/^[ \t]*$/{: a;N;/#matchee/!P;D;/^[ \t]*$/b a}' file.txt

is a loop of the following:

  • grab a line L1, and add it to the pattern space
  • if L1 is non-blank, print it; but if it is blank, then:
    • create label a ← this is a no-op, just a place to goto
    • grab another line, L2, and add it to the pattern space
    • if L2 does not contain #matchee, print L1
    • discard L1 from the pattern space (whether or not we printed it)
    • we can now think of L2 as L1; it's the only thing in the pattern space
    • if the rechristened L1 is blank, goto a
like image 193
ruakh Avatar answered Sep 25 '22 20:09

ruakh