如何使用grep在嵌套目录中搜索包含全部指定字符串的文件?
在嵌套目录中用grep搜索同时包含多个字符串的文件(交集搜索)
好问题!要在嵌套目录里找出同时包含foo、bar、bah这三个字符串的文件,确实不用反复用管道+xargs那么繁琐,这里有几种更简洁实用的方法:
方法1:用find结合多轮grep判断
这种方法兼容性最好,几乎所有系统都支持,而且能安全处理含特殊字符(比如空格、换行)的文件名:
find . -type f -exec sh -c 'grep -q "foo" {} && grep -q "bar" {} && grep -q "bah" {}' \; -print
- 解释:
find遍历当前目录下所有文件,对每个文件执行shell命令,用grep -q(静默模式,只返回匹配状态不输出内容)依次检查三个字符串是否都存在,全部满足就打印文件名。
方法2:用GNU grep的Perl正则(最简洁)
如果你用的是GNU grep(大部分Linux发行版默认都是),可以用Perl兼容正则表达式实现一次性匹配:
grep -rlP '(?s)(?=.*foo)(?=.*bar)(?=.*bah)' .
- 解释:
-r:递归遍历目录-l:只输出匹配的文件名-P:启用Perl正则语法(?s):让.匹配换行符,确保整个文件内容被当作一个整体处理(?=.*xxx):正向预查,确保文件中存在xxx字符串,三个预查同时满足才会匹配成功
方法3:优化版管道+xargs(处理特殊文件名)
如果你还是想用管道的方式,可以加上-Z和-0参数来避免文件名中的空格或特殊字符导致错误,比你原来的写法更健壮:
grep -rlZ "foo" . | xargs -0 grep -rlZ "bar" | xargs -0 grep -l "bah"
-Z:让grep输出文件名时用空字符(\0)分隔,而非换行-0:让xargs以空字符作为分隔符读取输入,彻底规避特殊文件名的问题
另外你提到的-F参数(固定字符串匹配,无需转义正则特殊字符)也可以结合这些方法使用,比如把上面的"foo"换成-F foo,适合搜索本身包含正则符号的字符串。
内容的提问来源于stack exchange,提问作者user3.1415927




