我使用命令递归查找包含特定
string1
的文件:
find . -type f -exec grep -H string1 {} \;
我需要查找包含多个字符串的文件,因此该命令应返回包含所有字符串的文件。像这样的东西:
find . -type f -exec grep -H string1 AND string2 {} \;
我找不到办法。字符串可以位于文件中的任何位置。即使只有两个字符串的解决方案也会很好。
你也可以试试这个;
find . -type f -exec grep -l 'string1' {} \; | xargs grep -l 'string2'
这显示包含 string1 和 string2 的文件名
您可以链接您的操作,并使用第一个操作的退出状态,仅在第一个操作成功时才执行第二个操作。 (省略原色之间的运算符默认为
-and
/-a
。)
find . -type f -exec grep -q 'string1' {} \; -exec grep -H 'string2' {} \;
第一个 grep 命令使用
-q
,“安静”,如果找到字符串,它会返回成功的退出状态。
要收集包含
string1
的所有文件,然后只需调用一次 grep 即可搜索 string2
,您可以使用 -exec ... {} +
:
find . -type f -exec grep -q 'string1' {} \; -exec grep 'string2' {} +
与 GNU
grep
grep -rlZ 'string1' | xargs -0 grep -l 'string2'
来自
man grep
-r, --递归
按照符号递归读取每个目录下的所有文件 仅当它们位于命令行上时才链接。注意如果没有文件 给定操作数,grep 搜索工作目录。这是 相当于 -d 递归选项。
-Z,--null 输出零字节(ASCII NUL 字符),而不是通常跟在文件后面的字符 姓名。 例如,grep -lZ 在每个文件名后输出一个零字节,而不是通常的换行符。 此选项使输出明确,即使存在包含异常的文件名 像换行符这样的字符。 此选项可与 find -print0、perl -0、sort -z 等命令一起使用 和 xargs -0 来处理任意文件名,甚至包含换行符的文件名。
惊讶于这个老问题缺乏明显简单的 Awk 解决方案:
find . -type f -exec awk '/string1/ && /string2/ { print; r=1 } END { exit 1-r }' {} \;
使用
r
变量的技巧只是模拟 grep
中的退出代码(零表示找到,1 表示未找到;如果您不在乎,可以将其删除)。
为了提高效率,也许从
-exec ... {} \;
切换到 -exec ... {} +
,不过你可能需要稍微重构一下 Awk 脚本(要么扔掉退出代码,要么更改它,以便退出代码指示“没有文件匹配”之类的内容) “仅部分文件匹配”与“所有文件匹配”?)
上面的代码查找在同一行包含两个字符串的文件。在任何线路上找到它们的情况都是一个简单的改变。
awk '/string1/ { s1=1 }
/string2/ { s2=1 }
s1 && s2 { print FILENAME; exit }
END { exit(1 - (s1 && s2)) }' file
这只是打印文件的名称,并假设您有一个输入文件。对于处理多个文件,请稍微重构,以在访问新文件时重置
s1
和 s2
的值:
awk 'FNR == 1 { s1 = s2 = 0 }
/string1/ { s1 = 1 }
/string2/ { s2 = 1 }
s1 && s2 { r=1; print FILENAME; nextfile }
END { exit 1-r }' file1 file2 file3 ...
一些古老的 Awk 版本可能不支持
nextfile
,尽管它现在已在 POSIX 中。
正如您从本页的其他答案中看到的,有几种命令行工具可用于跨文件执行联合搜索。尚未发布的快速灵活的解决方案是使用ag:
ag -l string1 | xargs ag -l string2
对于不区分大小写的搜索,请使用
-i
:的
ag
选项
ag -il string1 | xargs ag -il string2
对于其他搜索词,请扩展管道:
ag -l string1 | xargs ag -l string2 | xargs ag -l string3 | xargs ag -l string4
grep -rlZ string1 | xargs -0 grep -l string2
如果您的模式是固定字符串,我们可以通过在 grep 中添加
-F
来加快命令速度:
grep -rlZF string1 | xargs -0 grep -lF string2
这对我来说是最简单的(感谢 ChatGPT)。您可以添加任意数量的字符串
find /path/to/directory -type f -name '*string1*' -name '*string2*'