grep invert search with context

19,433

Solution 1

Give this a try:

sed 'h;:b;$b;N;N;/PATTERN/{N;d};$b;P;D' inputfile

You can vary the number of N commands before the pattern to affect the number of lines to delete.

You could programmatically build a string containing the number of N commands:

C=2 # corresponds to grep -C
N=N
for ((i = 0; i < C - 1; i++)); do N=$N";N"; done
sed "h;:b;\$b;$N;/PATTERN/{N;d};\$b;P;D" inputfile

Solution 2

If the lines are all unique you could grep the lines you want to remove into a file, and then use that file to remove the lines from the original, e.g.

grep -C 2 "line I don't want" < A.txt > B.txt
grep -f B.txt A.txt

Solution 3

awk 'BEGIN{n=2}{a[++i]=$0}
/dont/{
  for(j=1;j<=i-(n+1);j++)print a[j];
  for(o=1;o<=n;o++)getline;
  delete a}
END{for(i in a)print a[i]} ' file
Share:
19,433

Related videos on Youtube

aaronstacy
Author by

aaronstacy

i'm new graduate of Purdue's computer engineering program, i currently work at UT's Applied Research Lab, and i'm a former sergeant in the marine corps

Updated on January 21, 2020

Comments

  • aaronstacy
    aaronstacy over 4 years

    I want to filter out several lines before and after a matching line in a file.

    This will remove the line that I don't want:

    $ grep -v "line that i don't want"
    

    And this will print the 2 lines before and after the line I don't want:

    $ grep -C 2 "line that i don't want"
    

    But when I combine them it does not filter out the 2 lines before and after the line I don't want:

    # does not remove 2 lines before and after the line I don't want:
    $ grep -v -C 2 "line that i don't want"   
    

    How do I filter out not just the line I don't want, but also the lines before and after it? I'm guessing sed would be better for this...

    Edit: I know this could be done in a few lines of awk/Perl/Python/Ruby/etc, but I want to know if there is a succinct one-liner I could run from the command line.

  • n611x007
    n611x007 almost 12 years
    no, you mean grep just cannot do this?! is there a reason? it's counterintuitive for me
  • SourceSeeker
    SourceSeeker almost 12 years
    @naxa: When -C and -v are used together the -C includes excluded lines rather than excluding additional lines. Try this: printf '%s\n' {1..36} | grep --color -C 2 -v '^2.' and you'll see that 20, 21, 28 and 29 are included rather than 18, 19, 30 and 31 being excluded. The -C option is not specified by POSIX, by the way.
  • n611x007
    n611x007 almost 12 years
    ah I see. thank you very much for your concern and the nice example now in color! I've tried with -A and -B but they work alike -C. They also seem to be 'non-posix' now that I know what I missed to look for.
  • Dermot Canniffe
    Dermot Canniffe over 9 years
    I know you probably already know this since you've got way more XP than me, but you may want to add a little more explanation than just the code segment maybe, addressing the fact that the OP asked for a grep solution, while offering your otherwise very valid and extremely useful AWK solution. Thanks!
  • ghostdog74
    ghostdog74 over 9 years
    @DermotCanniffe, lol the accepted answer is even more convoluted using sed.
  • Dermot Canniffe
    Dermot Canniffe over 9 years
    Quite true. As much as I love sed, I think awk procedures are much easier to explicate. :)
  • buddyp450
    buddyp450 over 8 years
    I'm having a very hard time understanding what your one-liner sed does command-by-command even with the help of the man pages. I'll probably review later but if it's not too much trouble would you mind breaking it down? I think it would benefit the quality of the answer.
  • anatolyg
    anatolyg over 4 years
    This solution doesn't always work; see another answer for details.
  • stevesliva
    stevesliva over 3 years
    Can one-line this w/o a side file: grep -C1 unwanted A.txt | grep -vFf- A.txt ... this uses -f- which reads the 'file' from stdin. Also, I suggest -F for fixed strings.
  • stevesliva
    stevesliva over 3 years
    Finally, OP is missing -v