如何使用多个 AND 模式运行 grep?

如何使用多个 AND 模式运行 grep?

我想获得隐式的多模式匹配模式之间,即相当于按顺序运行多个 grep:

grep pattern1 | grep pattern2 | ...

那么如何将其转换为类似的东西呢?

grep pattern1 & pattern2 & pattern3

我想使用单个 grep 因为我正在动态构建参数,所以所有内容都必须适合一个字符串。使用过滤器是系统功能,而不是 grep,因此这不是它的论据。


不要将此问题与以下问题混淆:

grep "pattern1\|pattern2\|..."

这是一或者多模式匹配。我正在寻找一个模式匹配。

答案1

要查找与模式列表中的每个模式相匹配的行agrep(原始模式,现在随一瞥,而不是不相关的TRE 正则表达式库) 可以使用以下语法来完成:

agrep 'pattern1;pattern2'

使用 GNU grep,当使用 PCRE 支持构建时,您可以执行以下操作:

grep -P '^(?=.*pattern1)(?=.*pattern2)'

ASTgrep:

grep -X '.*pattern1.*&.*pattern2.*'

(添加.*s 作为<x>&<y>匹配字符串,同时匹配<x><y> 确切地a&b永远不会匹配,因为没有这样的字符串可以两者a并且b同时)。

如果模式不重叠,您也可以执行以下操作:

grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'

最好的便携方式可能是awk如上所述:

awk '/pattern1/ && /pattern2/'

或者与sed

sed -e '/pattern1/!d' -e '/pattern2/!d'

或者perl

perl -ne 'print if /pattern1/ && /pattern2/'

请注意,所有这些都有不同的正则表达式语法。

//不反映是否awk有任何行与其退出状态中的模式匹配。为了让你需要:sedperl

awk '/pattern1/ && /pattern2/ {print; found = 1}
     END {exit !found}'
perl -ne 'if (/pattern1/ && /pattern2/) {print; $found = 1}
          END {exit !$found}'

或者将命令通过管道传输到grep '^'.

对于潜在的 gzip 压缩文件,您可以使用zgrep,它通常是 的 shell 脚本包装器grep,并使用上面的解决方案之一grep(不是 ast-open 的解决方案,因为该grep实现不能被 使用zgrep),或者您可以使用其中的PerlIO::gzip模块perl输入时透明地解压缩文件:

perl -MPerlIO::gzip -Mopen='IN,gzip(autopop)' -ne '
  print "$ARGV:$_" if /pattern1/ && /pattern2/' -- *.gz

zgrep(如果文件足够小,至少比在内部完成解压缩而无需为每个文件运行更有效gunzip)。

答案2

您没有指定 grep 版本,这很重要。某些正则表达式引擎允许使用“&”通过 AND 进行多个匹配,但这是非标准且不可移植的功能。但是,至少 GNU grep 不支持这一点。

OTOH,您可以简单地将 grep 替换为 sed、awk、perl 等(按重量增加的顺序列出)。使用 awk,命令看起来像

awk '/regexp1/ && /regexp2/ && /regexp3/ { 打印; }'

并且它可以被构造为以简单的方式在命令行中指定。

答案3

git grep

这是使用的语法git grep使用组合多个模式布尔值表达式:

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3

上面的命令将立即打印匹配所有模式的行。

--no-index搜索当前目录中不受 Git 管理的文件。

检查man git-grep寻求帮助。

也可以看看:

为了或者操作见:

答案4

如果patterns每行包含一个模式,您可以执行以下操作:

awk 'NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1' patterns -

或者这匹配子字符串而不是正则表达式:

awk 'NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1' patterns -

要在空的情况下打印所有输入行而不是不打印输入行patterns,请替换NR==FNRFILENAME==ARGV[1], 或ARGIND==1in gawk

这些函数打印 STDIN 的行,其中包含指定为参数的每个字符串作为子字符串。ga代表 grep all 并gai忽略大小写。

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 "$@") -; }

相关内容