How to run grep with multiple AND patterns?
agrep
can do it with this syntax:
agrep 'pattern1;pattern2'
With GNU grep
, when built with PCRE support, you can do:
grep -P '^(?=.*pattern1)(?=.*pattern2)'
With ast grep
:
grep -X '.*pattern1.*&.*pattern2.*'
(adding .*
s as <x>&<y>
matches strings that match both <x>
and <y>
exactly, a&b
would never match as there's no such string that can be both a
and b
at the same time).
If the patterns don't overlap, you may also be able to do:
grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'
The best portable way is probably with awk
as already mentioned:
awk '/pattern1/ && /pattern2/'
With sed
:
sed -e '/pattern1/!d' -e '/pattern2/!d'
Please beware that all those will have different regular expression syntax.
You didn't specify grep version, this is important. Some regexp engines allow multiple matching groupped by AND using '&' but this is non-standard and non-portable feature. But, at least GNU grep doesn't support this.
OTOH you can simply replace grep with sed, awk, perl, etc. (listed in order of weight increasing). With awk, the command would look like
awk '/regexp1/ && /regexp2/ && /regexp3/ { print; }'
and it can be constructed to be specified in command line in easy way.
If patterns
contains one pattern per line, you can do something like this:
awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns -
Or this matches substrings instead of regular expressions:
awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -
To print all instead of no lines of the input in the case that patterns
is empty, replace NR==FNR
with FILENAME==ARGV[1]
, or with ARGIND==1
in gawk
.
These functions print the lines of STDIN which contain each string specified as an argument as a substring. ga
stands for grep all and gai
ignores case.
ga(){ awk 'FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1' <(printf %s\\n "$@") -; }
gai(){ awk 'FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1' <(printf %s\\n "$@") -; }