Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

grep invert search with context

Tags:

grep

shell

unix

sed

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.

like image 633
aaronstacy Avatar asked Oct 06 '10 15:10

aaronstacy


People also ask

How do I reverse grep search?

In order to invert a grep expression, we just need to make use of the -v flag along with the grep command.

What is the opposite of grep?

The long form of the flag -v is --invert-match .

How do you grep at the end of a line?

Matching the lines that end with a string : The $ regular expression pattern specifies the end of a line. This can be used in grep to match the lines which end with the given string or pattern.


3 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
like image 136
Emery Lapinski Avatar answered Oct 11 '22 03:10

Emery Lapinski


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
like image 24
Dennis Williamson Avatar answered Oct 11 '22 03:10

Dennis Williamson


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
like image 27
ghostdog74 Avatar answered Oct 11 '22 01:10

ghostdog74