Grep Invert Search with Context

Grep Invert Search with Context

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.

0

6 Answers

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
2

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
4
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
3

I solved it with two sequential grep, actually. It seems way more straightforward to me.

grep -C "match" yourfile | grep -v -f - yourfile
1

I think @fxm27 has an excellent, bash-y answer.

I would add that you could solve this another way by using egrep if you knew in advance the patterns of the subsequent lines.

command | egrep -v "words|from|lines|you|dont|want"

That will do an "inclusive OR", meaning that a line that matches any of those will be excluded.

2019 Solution

This is a simple solution, found elsewhere:

grep --invert-match "test*"

Selects all not matching "test*". Super useful and easy to remember!

(Edit)

This doesn't completely answer the original question and returns the entire set of lines not matching.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

James H. Sterling
Author

James H. Sterling

James Sterling reports on renewable energy developments, climate policy, ecological conservation, and green tech innovations around the globe.