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?
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
How about
sed '/pattern/ {$!N;d;}' file
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
.
Most sed
s 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
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).