To and
together multiple searches, use multiple lookahead assertions, one per thing looked for apart from the last one:
instead of writing
grep -P A * | grep B
you write
grep -P '(?=.*A)B' *
grep -Pr '(?=.*db-connect\.php)version' .
Don’t write
grep -P 'A.*B|B.*A' *
because that fails on overlaps, whereas the (?=…)(?=…)
technique does not.
You can also add in NOT
operators as well. To search for lines that don’t match X
, you normally of course use -v
on the command line. But you can’t do that if it is part of a larger pattern. When it is, you add (?=(?!X).)*$)
to the pattern to exclude anything with X
in it.
So imagine you want to match lines with all three of A, B, and then either of C or D, but which don’t have X or Y in them. All you need is this:
grep -P '(?=^.*A)(?=^.*B)(?=^(?:(?!X).)*$)(?=^(?:(?!Y).)*$)C|D' *
In some shells and in some settings. you’ll have to escape the !
if it’s your history-substitution character.
There, isn’t that pretty cool?