Unix命令列出包含某个字符串但*不*包含另一个字符串的文件

34

如何递归查看一个包含某个字符串但不包含另一个字符串的文件列表?同时,我想要评估文件的文本内容而不是文件名。


结论:

根据评论,我最终使用了:

find . -name "*.html" -exec grep -lR 'base\-maps' {} \; | xargs grep -L 'base\-maps\-bot'

这返回的是“base-maps”文件而不是“base-maps-bot”,谢谢!!


1
最简单的方法是使用 grep -l 列出与模式匹配的文件,然后将其管道传输到 grep -v - Mikel
适用于http://superuser.com。 - Paul R
2
Mikel:但是它只会将文件名传递到另一个grep,然后只能从这些文件名中过滤,而不能过滤文件内容。 - Alan Haggai Alavi
我已经尝试过了,并且同意Alan的观点,它只过滤文件名。因此,它并没有达到我所希望的目的。 - Matrym
@Alan 你不能传递一个文件集给grep吗?如果可以的话,难道不能基于另一个grep传递一个文件集吗?这只是我想象的可能性,但如果有人知道如何做到这一点,那就太棒了 :D - Matrym
Matrym:类似于 ls -1 *.html | xargs grep -l '<foo>' - | xargs grep -L '<bar>' - 的操作可以像Sander Marechal所述那样完成。 - Alan Haggai Alavi
6个回答

48

试试这个:

grep -rl <string-to-match> | xargs grep -L <string-not-to-match>

解释:使用grep -lr可以让grep递归地(r)输出包含<string-to-match>的所有文件的列表(l)。xargs循环遍历这些文件,在每个文件上调用grep -L。当文件不包含<string-not-to-match>时,grep -L仅会输出文件名。


grep字符串应该加引号还是转义?是和否。 - Matrym
7
@Matrym 的命令行指令翻译如下:在当前目录下查找所有后缀为 .html 的文件,并在这些文件中搜索包含指定字符串 <string-to-match> 的文件名,再使用 xargs 命令筛选出不包含另一个指定字符串 <string-not-to-match> 的文件名。 - chrisaycock
1
太棒了。真是太棒了。太太太棒了。 - Matrym
@Matrym 不要在 find 中使用 -R,因为它已经是递归的了。只有在单独使用 grep 时才使用 -R - chrisaycock
你可以使用 ack-grep 命令来使第一个命令更加高效:ack-grep -al <string-to-match> 或者在你的情况下,ack-grep --html -l <string-to-match>。 - Gerry
显示剩余2条评论

3

在上面的答案中使用xargs是不必要的;你可以按照以下方式实现相同的效果:

find . -type f -exec grep -q <string-to-match> {} \; -not -exec grep -q <string-not-to-match> {} \; -print
grep -q 表示静默运行但返回一个退出码,指示是否找到匹配项;find 可以使用该退出码来确定是否继续执行其余的选项。如果 -exec grep -q <string-to-match> {} \; 返回 0,则会继续执行 -not -exec grep -q <string-not-to-match>{} \;。如果这也返回 0,则会继续执行 -print,它会打印文件名。
正如另一个答案所指出的那样,在你只想搜索某种类型的文件时,使用这种方式的 findgrep -Rl 有很大的优势。另一方面,如果你真的想搜索所有文件,grep -Rl 可能更快,因为它使用一个 grep 进程来执行所有文件的第一个过滤器,而不是每个文件都使用一个单独的 grep 进程。

1

这些答案似乎有误,因为匹配到了两个字符串。以下命令应该更好:

grep -l <string-to-match> * | xargs grep -c <string-not-to-match> | grep '\:0'

1
这里是一个更通用的结构:


find . -name <nameFilter> -print0 | xargs -0 grep -Z -l <patternYes> | xargs -0 grep -L <patternNo>

这个命令会输出文件名与<nameFilter>匹配(根据需要调整find谓词),且包含<patternYes>但不包含<patternNo>的文件。
增强功能包括:
  • 可以处理文件名中包含空格的情况。
  • 可以按名称过滤文件。
如果您不需要按名称过滤(通常希望考虑当前目录中的所有文件),则可以去掉find并在第一个grep中添加-R
grep -R -Z -l <patternYes> | xargs -0 grep -L <patternNo>

0

查找 . -maxdepth 1 -name "*.py" -exec grep -L "string-not-to-match" {} \;

该命令将获取同一目录下所有不包含“string-not-to-match”的“.py”文件。


0
为了匹配字符串A并排除同时存在于同一行的字符串B和C,我使用引号来允许搜索字符串包含空格。
grep -r <string A> | grep -v -e <string B> -e "<string C>" | awk -F ':' '{print $1}'

说明:grep -r 递归地过滤所有匹配输出格式的行

文件名:行号

为了排除(grep -v)那些也包含-e字符串B或-e字符串C的行。使用awk仅打印第一个字段(文件名),使用冒号作为字段分隔符-F。


请为您的代码添加一些解释以获取更多信息。 - Farbod Ahmadian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接