我想获得隐式的多模式匹配和模式之间,即相当于按顺序运行多个 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
有任何行与其退出状态中的模式匹配。为了让你需要:sed
perl
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
答案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==FNR
为FILENAME==ARGV[1]
, 或ARGIND==1
in 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 "$@") -; }