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

gre*_*man 117 grep regular-expression

我想通过模式之间的隐式AND获得多模式匹配,即相当于在一个序列中运行几个 grep:

grep pattern1 | grep pattern2 | ...
Run Code Online (Sandbox Code Playgroud)

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

grep pattern1 & pattern2 & pattern3
Run Code Online (Sandbox Code Playgroud)

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


不要将此问题与:

grep "pattern1\|pattern2\|..."
Run Code Online (Sandbox Code Playgroud)

这是一个OR多模式匹配。

Sté*_*las 103

agrep 可以使用以下语法来做到这一点:

agrep 'pattern1;pattern2'
Run Code Online (Sandbox Code Playgroud)

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

grep -P '^(?=.*pattern1)(?=.*pattern2)'
Run Code Online (Sandbox Code Playgroud)

astgrep

grep -X '.*pattern1.*&.*pattern2.*'
Run Code Online (Sandbox Code Playgroud)

(添加.*S作为<x>&<y>匹配字符串匹配都<x><y> 准确a&b将不会匹配,因为没有这样的字符串,可以两个a,并b在同一时间)。

如果模式不重叠,您也可以这样做:

grep -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'
Run Code Online (Sandbox Code Playgroud)

最好的便携方式可能awk是已经提到的:

awk '/pattern1/ && /pattern2/'
Run Code Online (Sandbox Code Playgroud)

sed

sed -e '/pattern1/!d' -e '/pattern2/!d'
Run Code Online (Sandbox Code Playgroud)

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

  • `agrep` 语法对我不起作用......它是在哪个版本中引入的? (3认同)
  • @Raman,你的听起来像 [TRE `agrep`](https://github.com/laurikari/tre/)。 (2认同)
  • @Techiee,或者只是`awk '/p1/ &amp;&amp; /p2/ {n++}; END {打印 0+n}'` (2认同)
  • @DanielKaplan,从你最近的问题来看,我怀疑你正在寻找与本问答内容不同的东西。在这里,我们试图找到与所有模式匹配的*行*,而您可能试图找到所有模式都与任何行匹配的*文件*(这里有几个问答涵盖了这一点)。我编辑了答案,也许会让这一点更加明显。 (2认同)

Net*_*tch 24

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

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

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

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

  • 请记住`awk` 使用ERE,例如相当于`grep -E`,而不是普通`grep` 使用的BRE。 (4认同)
  • `awk` 的正则表达式被*称为* ERE,但实际上它们有点特殊。这里可能有比任何人都关心的更多细节:http://wiki.alpinelinux.org/wiki/Regex (4认同)
  • 默认操作是打印匹配的行,因此 `{ print; }` 部分在这里并不是真正必要或有用的。 (3认同)

nis*_*ama 11

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

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

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

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

要在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 "$@") -; }
Run Code Online (Sandbox Code Playgroud)


ole*_*enb 9

grep pattern1 | grep pattern2 | ...

我想使用单个 grep 因为我正在动态构建参数,所以所有内容都必须放在一个字符串中

实际上可以动态构建管道(无需求助于eval):

# Executes: grep "$1" | grep "$2" | grep "$3" | ...
function chained-grep {
    local pattern="$1"
    if [[ -z "$pattern" ]]; then
        cat
        return
    fi    

    shift
    grep -- "$pattern" | chained-grep "$@"
}

cat something | chained-grep all patterns must match order but matter dont
Run Code Online (Sandbox Code Playgroud)

不过,这可能不是一个非常有效的解决方案。

  • 使用“chained-grep()”或“function chained-grep”,但不要使用“function chained-grep()”:https://unix.stackexchange.com/questions/73750/difference- Between-function-foo-and -foo (2认同)

ken*_*orb 9

git grep

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

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3
Run Code Online (Sandbox Code Playgroud)

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

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

检查man git-grep帮助。

也可以看看:

对于OR操作,请参阅:

  • 仅当找到与所有模式匹配的行时,这才会匹配文件,而不是模式与各个行匹配的文件。使用“--all-match”和“--or”而不是“--and”。 (4认同)