Remove line with the pattern match and the next line

I am trying to remove all instances of a pattern match from a file if it matches a pattern. If there is a match, the (complete) line with the matching pattern and the next line get removed.

The next line always appears after the line with the pattern match, but in addition it appears in other areas of the file.

I am using grep and it is deleting all occurrences of the next line in the file, as expected.

Is there a way I can remove that next line if and only if it is after the line with the pattern match?

Asked By: kenuse

||
cat sample
Pattern line
next after pattern line
this is another
random line
next after pattern line
has occured without.
now we have
another 
Pattern line
next after pattern line
let us see the output.

Now, I issue the below command.

sed -e '/Pattern line/,+1d' sample

This is the output I am getting.

this is another
random line
next after pattern line
has occured without.
now we have
another 
let us see the output.

next after pattern line is not removed when it occurs as a separate line not next to the pattern.

As per Michael’s comments, the above syntax is GNU extension. You can try something like,

sed -e '/Pattern line/{N;d}' sample
Answered By: Ramesh

How about

sed '/pattern/ {$!N;d;}' file
Answered By: steeldriver

You can use sed with the N and d commands and a {} block:

sed -e '/pattern here/ { N; d; }'

For every line that matches pattern here, the code in the {} gets executed. N takes the next line into the pattern space as well, and then d deletes the whole thing before moving on to the next line. This works in any POSIX-compatible sed.

Answered By: Michael Homer

Most seds do not print the last line if you N on $. But GNU sed will. So if the pattern you want deleted is on the last line and you N it will print. It is sometimes better to keep the buffer full – as in, always holding 2 lines except on the lines you do not want to print. You might do so like:

seq 10 | sed -n 'x;/7/!g;//!p'

That’s an example with seq as input. On every line it swaps hold space and pattern space. If the last held line does not match a 7 (in this case) it will overwrite the hold space with the current line. It then checks again that the line it just pulled in – the current line – also does not match the 7, otherwise it will not print it. So on every line it checks the previous and the current line.

1
2
3
4
5
6
9
10

And if your pattern does fall on the last line:

seq 10 | sed -n 'x;/10/!g;//!p' 

1
2
3
4
5
6
7
8
9

Another example, to hopefully demonstrate more clearly what it will and will not print:

sed -n 'x;/match/!g;//!p
' <<DATA
    match 
    match 
    1not 
    2not 
    3not 
    4not 
    5not 
    match 
    6not 
    match                                                              
DATA

OUTPUT

2not
3not
4not
5not
Answered By: mikeserv

An awk solution:

awk '/pattern/    { matched=1; next }
     1 == matched { matched = 0; next }
                  { print }' input-file

Line 1 looks for lines matching the pattern, sets a flag, and skips the line. Line 2 skips a line when the flag is set, but resets the flag. Line 3 prints lines that weren’t skipped by one of the other two lines.

You can type this on one line if you like:

awk '/pattern/{matched=1;next} 1==matched{matched=0;next} {print}' input-file

Here’s a variation that lets you control how many lines to skip:

awk '/pattern/{skip=3;next} skip>0{--skip;next} {print}' input-file

Set skip to the number of lines that should be skipped (in addition to the matched line).

Answered By: Kenster
Categories: Answers Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.