Grep to find instances of “Foo” where “Bar” does not appear within 10 lines

grep

Suppose I want to search an entire tree for all CPP files where "Foo" occurs. I might do:

find . -name "*.cpp" | xargs grep "Foo"

Now suppose I want to list only those instances where some other string, say "Bar" does not occur within 3 lines of the previous result.

So given two files:

a.cpp

1 Foo
2 qwerty
3 qwerty

b.cpp

1 Foo
2 Bar
3 qwerty

I would like to construct a simple search where "Foo" from a.cpp is found, but "Foo" from b.cpp is not.

Is there a way to accomplish this in a fairly simple way?

Best Answer

With pcregrep:

pcregrep --include='\.cpp$' -rnM 'Foo(?!(?:.*\n){0,2}.*Bar)' .

The key is in the -M option which is unique to pcregrep and is used to match multiple lines (pcregrep pulls more data from the input file as necessary when walking the RE demands it).

(?!...) is the perl/PCRE negative look-ahead RE operator. Foo(?!...) matches Foo as long as ... does not match what follows.

... being (?:.*\n){0,2}.*Bar (. not matching a newline character), that is from 0 to 2 lines followed by a line containing Bar.

Related Question