如何使用 grep 搜索文件中的多个字符串(交集搜索)

如何使用 grep 搜索文件中的多个字符串(交集搜索)

如何使用 grep 在嵌套目录结构中搜索包含以下内容的文件全部我的搜索模式中的单词?

我想 grep 查找包含多个单词的文件 - 让我们使用 foo bar 和 bah。我可以grep -rl foo |xargs grep -rl bah| ...etc,但是有更简单的方法吗?我知道我可以使用 -F 作为要搜索的字符串文件,但我相信这仍然使用 OR 运算符(并集)搜索字符串,并且我需要使用 AND 运算符(交集)。

答案1

find+awk解决方案:

find . -type f -exec awk '/\<foo\>/{ p1=1 }/\<bar\>/{ p2=1 }/\<bah\>/{ p3=1 }
                          p1 && p2 && p3{ print FILENAME; exit }' {} +

awk节目详情:

  • /\<foo\>/{ p1=1 }/\<bar\>/{ p2=1 }/\<bah\>/{ p3=1 }- 遇到每个所需的模式时 - 设置相应的标志
  • p1 && p2 && p3- 一旦找到所有模式:
    • print FILENAME- 打印当前的文件名/文件路径
    • exit- 立即退出脚本执行

答案2

我的答案与@RomanPerekhrest 的答案类似。主要区别在于,它利用了这样一个事实:通过将记录分隔符 ( ) 设置为永远不会与输入中的任何内容匹配的内容(例如),您可以awk一次性处理整个输入。换句话说,吞入整个文件并像搜索单个字符串一样搜索它。RS^$

例如

find . -type f -exec \
  awk -v RS='^$' '/foo/ && /bar/ && /baz/ { print FILENAME }' {} +

这将列出当前目录 ( .) 下包含的所有文件全部正则表达式foo, bar, 和baz.如果您需要将任何或所有正则表达式视为整个单词,请用单词边界锚点将它们包围起来\<-\>例如\<foo\>

这也运行得更快,因为它不会awk为每个文件分叉一次。相反,它awk以适合命令行缓冲区的尽可能多的文件名参数运行(在现代系统上通常为 128K 或 1 或 2M 字符)....例如,如果find发现 1000 个文件,它只会运行awk一次而不是 1000 次。

笔记:这需要一个awk允许RS成为正则表达式的版本。看awk 中的 Slurp 模式?有关更多详细信息以及如何在 awk 的其他版本中实现有限形式的“slurp 模式”的示例,请阅读。

另请注意:这会将找到的每个文件的全部内容读入内存,一次一个。对于真正巨大的文件,例如数十 GB 或更大的日志文件,这可能会超出可用 RAM 甚至 RAM+SWAP。尽管这种情况不太可能发生,但一旦发生就会导致严重问题(例如,在 Linux 上,如果运行 RAM 和 SWAP 不足,内核将开始杀死随机进程)。

答案3

对于这样的逻辑与,我通常会依靠awk

awk '/foo/ && /bar/ && /bah/ { print }' /path/to/file

答案4

使用 GNUgrep-P (Perl 兼容性)选项和正向前瞻正则表达式(?=(regex))在单行或整个文件中以任意顺序查找单词,并在从当前目录开始找到的所有文件中递归查找。

grep -rlP '(?s)(?=.*?\bfoo\b)(?=.*?\bbar\b)(?=.*?\bbah\b)' .
  • (?s)这是 DOTALL 修饰符并允许为了匹配 \newlines,我们会(.|\n)*?在单词之间使用 Too 以及[\s\S]*?

  • \bWORD\b;\b是单词边界锚点。

输入如下:

==> file1 <==
foo here and bar
bah
and of file1

==> file2 <==
foo then bar and bah

==> file3 <==
foo foobarbah ba

==> file4 <==
this is foo bar bahh
bah

输出是:

./file1
./file2
./sub-dir/file4

相关内容