Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question
3  
Please add some example input and output. I think I know what you're trying to do; and it would be easy to do with awk, but I'd like to make sure I'm clear on what you want before I post an answer. –  HalosGhost Aug 26 at 22:05
2  
Welcome to U&L, please try and include some example data of what you're asking for. It's difficult to parse what you want w/o it, as is evidence in the A'ers you're receiving. They all work slightly different and are making this a bit of a messy Q&A. –  slm Aug 27 at 1:26

5 Answers 5

up vote 1 down vote accepted

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.

share|improve this answer
    
This doesn't appear to work, try using mikeserv's sample data w/ it. –  slm Aug 27 at 1:10
    
The main pattern never appears on the last line of the input, per the question. –  Michael Homer Aug 27 at 1:31
    
Where did you read that in the main Q? I'm missing that condition. –  slm Aug 27 at 1:40
    
"The next line always appears after the line with the pattern match" implies that there must be a following line, and so the main pattern can't ever occur on the last line. –  Michael Homer Aug 27 at 1:48
    
We'll wait for the OP, b/c I didn't not read that line at all like that. As I mentioned in steeldriver's A. Oh well, we wait, no biggie. –  slm Aug 27 at 1:51

How about

sed '/pattern/ {$!N;d;}' file
share|improve this answer
    
This doesn't appear to work, try using mikeserv's sample data w/ it. –  slm Aug 27 at 1:09
    
However the question says [t]he next line always appears after the line with the pattern match –  steeldriver Aug 27 at 1:18
    
Yeah this Q is poorly written IMO. I've read that statement 10 times and do not understand what it's actually saying. I think he needs to include sample data and clean it up or we should just close it. –  slm Aug 27 at 1:24
    
How about now (changed N to $!N)? –  steeldriver Aug 27 at 1:26
    
That's consistent with Mike's output now (assuming he's constructed it right) 8-) –  slm Aug 27 at 1:27

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
share|improve this answer
1  
Using the example from this A, this appears to be the only one that handles the edge scenarios properly. –  slm Aug 27 at 1:12
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
share|improve this answer
1  
Note that +1 is a GNU extension. –  Michael Homer Aug 26 at 22:09
    
@MichaelHomer, thanks. I have included the changes you specified. –  Ramesh Aug 26 at 22:14

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.