grep invert search with context
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
Related videos on Youtube
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, 2020Comments
-
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 almost 12 yearsno, you mean
grep
just cannot do this?! is there a reason? it's counterintuitive for me -
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 almost 12 yearsah 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 over 9 yearsI 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 over 9 years@DermotCanniffe, lol the accepted answer is even more convoluted using sed.
-
Dermot Canniffe over 9 yearsQuite true. As much as I love sed, I think awk procedures are much easier to explicate. :)
-
buddyp450 over 8 yearsI'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 over 4 yearsThis solution doesn't always work; see another answer for details.
-
stevesliva over 3 yearsCan 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 over 3 yearsFinally, OP is missing
-v