如何使用grep匹配同一行中的多个字符串?

hea*_*xas 204 regex linux string grep

我试图用来grep匹配包含两个不同字符串的行.我尝试了以下但是这匹配包含string1 string2的行,这不是我想要的.

grep 'string1\|string2' filename
Run Code Online (Sandbox Code Playgroud)

那么我如何grep只匹配包含两个字符串的行?

小智 196

我认为这就是你要找的东西:

grep -E "string1|string2" filename
Run Code Online (Sandbox Code Playgroud)

我认为答案是这样的:

grep 'string1.*string2\|string2.*string1' filename
Run Code Online (Sandbox Code Playgroud)

只匹配两者都存在的情况,而不是一个或两个或两者.

  • 这是如何为string1或string2 grep.问题清楚地表明他们正在寻找string1和string2. (24认同)
  • 不会`grep -e"string1"-e"string2"filename`也一样吗? (14认同)
  • 很确定问题非常精确:"如何匹配包含*两个*字符串的行?" (8认同)
  • 对于一个密切相关的问题,它仍然是一个有用的答案,它将把人们带到这里。以我为例,显然还有近 200 个人。 (3认同)
  • egrep'tring1 | string2 | string3'文件名也可以. (2认同)
  • 为什么这个答案还在这里?这不是问题的答案。 (2认同)

dhe*_*aur 177

您可以使用 grep 'string1' filename | grep 'string2'

要么, grep 'string1.*string2\|string2.*string1' filename

  • 仅在'string1'和'string2'位于同一行时才有效.如果要查找带有'string1'或'string2'的行,请参阅user45949的答案. (20认同)
  • 第一个选项:将一个grep传递给一个不会产生OR结果,它会产生一个AND结果. (9认同)
  • 我使用了`grep -e "string1" -e "string2"` (6认同)
  • 这个问题明确要求找到两个字符串(AND),而这个答案正是提供了这一点。 (5认同)
  • @AlexanderN确实我不能让它与多线工作,这太奇怪了它被接受.. (4认同)
  • 尝试多线 (3认同)

Kin*_*xit 26

要在任何地方搜索包含所有单词的文件:

grep -ril \'action\' | xargs grep -il \'model\' | xargs grep -il \'view_type\'
Run Code Online (Sandbox Code Playgroud)

第一个grep启动递归搜索(r),忽略case(i)并列出(打印出)l一个术语('action'带有单引号)匹配的文件的名称(在单个引号中)出现在文件的任何位置.

随后的greps搜索其他术语,保留不区分大小写并列出匹配的文件.

您将获得的最终文件列表将是包含这些术语的文件,可以按文件中的任何顺序排列.

  • 同意!我只是要注意,我必须给xargs一个"-d'\n'"来处理带空格的文件名.这适用于Linux:`grep -ril'foo'| xargs -d'\n'grep -il'bar'` (2认同)

tch*_*ist 15

如果你有一个有限正则表达式grep-P选项perl,你可以使用

grep -P '(?=.*string1)(?=.*string2)'
Run Code Online (Sandbox Code Playgroud)

它具有处理重叠字符串的优点.使用perlas 稍微简单一点grep,因为您可以更直接地指定和逻辑:

perl -ne 'print if /string1/ && /string2/'
Run Code Online (Sandbox Code Playgroud)

  • 最佳答案。Shell 非常简单快捷,但是一旦模式变得复杂,您应该使用 Python 或 Perl(或 Awk)。不要用头撞墙试图证明它可以在纯 shell 中完成(无论现在这意味着什么)。提醒大家,这些工具可以在“单行”语法中使用,这些语法嵌入到现有的 shell 脚本中。 (2认同)

Leo*_*Leo 12

你的方法几乎是好的,只缺少-w

grep -w 'string1\|string2' filename
Run Code Online (Sandbox Code Playgroud)

  • OP通过匹配string1 _or_ string2显示了一个示例,并询问如何匹配包含_both_字符串的行。此示例仍然产生OR。 (2认同)

Ed *_*ton 8

不要尝试使用 grep 来执行此操作,而是使用 awk。要在 grep 中匹配 2 个正则表达式 R1 和 R2,您可能会认为:

grep 'R1.*R2|R2.*R1'
Run Code Online (Sandbox Code Playgroud)

而在 awk 中则为:

awk '/R1/ && /R2/'
Run Code Online (Sandbox Code Playgroud)

但如果R2与 重叠或者是 的子集怎么办R1?grep 命令根本不起作用,而 awk 命令却可以。假设您想要查找包含the和 的行heat

$ echo 'theatre' | grep 'the.*heat|heat.*the'
$ echo 'theatre' | awk '/the/ && /heat/'
theatre
Run Code Online (Sandbox Code Playgroud)

你必须使用 2 个 grep 和一个管道:

$ echo 'theatre' | grep 'the' | grep 'heat'
theatre
Run Code Online (Sandbox Code Playgroud)

当然,如果您实际上要求它们分开,您始终可以在 awk 中编写与 grep 中使用的相同的正则表达式,并且还有替代的 awk 解决方案,这些解决方案不涉及在每个可能的序列中重复正则表达式。

抛开这一点,如果您想扩展您的解决方案以匹配 3 个正则表达式 R1、R2 和 R3,该怎么办?在 grep 中,这将是以下糟糕的选择之一:

grep 'R1.*R2.*R3|R1.*R3.*R2|R2.*R1.*R3|R2.*R3.*R1|R3.*R1.*R2|R3.*R2.*R1' file
grep R1 file | grep R2 | grep R3
Run Code Online (Sandbox Code Playgroud)

而在 awk 中则简洁、明显、简单、高效:

awk '/R1/ && /R2/ && /R3/'
Run Code Online (Sandbox Code Playgroud)

现在,如果您实际上想要匹配文字字符串 S1 和 S2 而不是正则表达式 R1 和 R2,该怎么办?您根本无法在一次调用 grep 中做到这一点,您必须在调用 grep 之前编写代码来转义所有 RE 元字符:

S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'
Run Code Online (Sandbox Code Playgroud)

或者再次使用 2 个 grep 和一个管道:

grep -F 'S1' file | grep -F 'S2'
Run Code Online (Sandbox Code Playgroud)

这又是糟糕的选择,而使用 awk 你只需使用字符串运算符而不是正则表达式运算符:

awk 'index($0,S1) && index($0.S2)'
Run Code Online (Sandbox Code Playgroud)

现在,如果您想在一个段落而不是一行中匹配 2 个正则表达式该怎么办?无法在 grep 中完成,在 awk 中微不足道:

awk -v RS='' '/R1/ && /R2/'
Run Code Online (Sandbox Code Playgroud)

跨越整个文件怎么样?再次无法在 grep 中完成,在 awk 中微不足道(这次我使用 GNU awk 进行多字符 RS 以便简洁,但在任何 awk 中都没有更多代码,或者您可以选择一个您知道不会的控制字符在 RS 的输入中执行相同操作):

awk -v RS='^$' '/R1/ && /R2/'
Run Code Online (Sandbox Code Playgroud)

因此,如果您想在一行、段落或文件中查找多个正则表达式或字符串,那么不要使用 grep,而应使用 awk。


mar*_*eno 7

|正则表达式中的运算符表示或.也就是说string1或string2匹配.你可以这样做:

grep 'string1' filename | grep 'string2'
Run Code Online (Sandbox Code Playgroud)

这会将第一个命令的结果传递给第二个grep.这应该只给你两条线匹配.

  • 这确实回答了这个问题,这确实是大多数人写它的方式。 (2认同)

Dor*_*orn 7

你可以尝试这样的事情:

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


tin*_*ink 7

正如人们建议的 perl 和 python 以及复杂的 shell 脚本,这里有一个简单的awk方法:

awk '/string1/ && /string2/' filename
Run Code Online (Sandbox Code Playgroud)

查看了对已接受答案的评论:不,这不支持多行;但这也不是问题作者所要求的。

  • 这不是问题的唯一正确答案,但却是最优雅的。它说明了使用正确工具完成工作的原则。 (2认同)