10

I need to search a file for a string, remove any line that contains the string, and also remove the two lines following any line that contains the string. I was hoping I could accomplish this using something like this...

$ grep -v -A 2 two temp.txt
one
five
$

...but unfortunately this did not work. Is there a simple I can do this with grep or another shell command?

Zombo
  • 1
  • 62
  • 391
  • 407
Daniel Standage
  • 8,136
  • 19
  • 69
  • 116

4 Answers4

7

The following works both with GNU sed and with OS X.

$ sed '/two/{N;N;d;}' temp.txt
one
five
  • find line matching two
  • read in two more lines
  • delete them
Daniel Standage
  • 8,136
  • 19
  • 69
  • 116
Zombo
  • 1
  • 62
  • 391
  • 407
  • Both your answer and @JohnKugelman's are concise, they both work on GNU/Linux, and neither work on OS X (not a huge deal for me for this particular task). For providing a brief explanation of the syntax, the accepted answer goes to you. Thanks. – Daniel Standage Apr 17 '13 at 02:48
  • 2
    Add a semicolon after the d and. Enforce the brace and it should work on MacOS X too. – Jonathan Leffler Apr 17 '13 at 05:03
3

With GNU sed:

sed '/two/,+2d' temp.txt

This uses two-address syntax (addr1,addr2) to match lines with the word two (/two/) plus the two lines after (+2). The d command deletes those lines.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • The only thing I can think of is that maybe they're using a older, non-GNU sed, without the `+number` option. But since it works (and I dislike drive-by downvoters), here's a vote to reverse it. – paxdiablo Apr 17 '13 at 02:31
3

You can do this with awk, as per the following transcript:

pax> echo 'one
two
three
four
five' | awk '/two/ {skip=3} skip>0 {skip--;next} {print}'

one
five

It basically starts a counter of lines to throw away (3) whenever it finds the two string on a line. It then throws those lines away until the skip counter reaches zero. Any line that isn't marked for skipping is printed.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1

Here's a way to do it with Perl:

$ perl -ne'if (/two/){$x=<>;$x=<>;}else{print}' temp.txt 
one
five

The -n is an implicit loop over the input. If you match /two/, then read the next two lines, otherwise print the line you're on.

The problem is, however, that if you had the third or fourth lines matched /two/, then you would still get the same output. @paxdiablo's solution is more complete. But mine's more Q&D.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152