如何查找不包含指定字符串模式的文件?

741

如何使用 grep 命令查找当前目录中不包含单词 foo 的文件?

18个回答

1067

如果你的grep命令带有-L选项(或--files-without-match):

$ grep -L "foo" *

1
如其他地方所指出,ack默认情况下可以帮助避免处理.svn(subversion)文件。 - GuruM
15
在GNU grep中,可以通过导出变量GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git'来实现这一点 :^) - bufh
9
或者使用ag的等效命令:ag -L 'foo' - bishop
1
如果您想查找名称中不包含多个特定内容的文件,该怎么办?可以使用命令 grep -L "foo,bar,baz" *。 - fIwJlxSzApHEZIl
12
神奇的效果!提示:使用“-rL”而不是“-L”来匹配子目录。 - Ufos
显示剩余8条评论

97

你可以只使用grep来完成这个任务(而不需要使用find)。

grep -riL "foo" .

这是对grep使用的参数进行说明。

     -L, --files-without-match
             each file processed.
     -R, -r, --recursive
             Recursively search subdirectories listed.

     -i, --ignore-case
             Perform case insensitive matching.
如果您使用小写字母的 l,则会得到相反的结果(具有匹配项的文件)。
     -l, --files-with-matches
             Only the names of files containing selected lines are written

50

看一下ack。它会自动为您排除.svn,提供Perl正则表达式,只需下载一个Perl程序即可。

您要查找的等效内容应该在ack中:

ack -L foo

31
以下命令将给出所有不包含模式foo的文件:
```bash grep -L "foo" * ```
find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0

6
您想将末尾的 grep 0 更改为 grep 0$ (否则会在文件名中包含字符 0 的文件中出现错误匹配)。 - clouseau
11
@clouseau大部分是正确的...... 但是,grep '0$'会匹配具有10行倍数的文件!您需要在结尾处使用grep ':0$'来检查是否有明确的“:0”在行末。然后,您将只获得与零行匹配的文件。 - TrinitronX
我所使用的UNIX系统没有带有这些选项的find或grep版本,因此我不得不使用其他评论中建议的“ack”命令。 - KC Baltz
1
非常低效,因为查找将不得不查找所有文件,包括那些包含“foo”的文件,然后在第二个进程中将它们丢弃。对于寻找大量文件的情况,这种方法效果不佳。应该提供一种使用内置的查找参数的解决方案。 - Daniel J.

17

以下命令使用第二个grep来排除需要find过滤的svn文件夹。

grep -rL "foo" ./* | grep -v "\.svn"

16

如果您使用Git,则此命令将搜索所有已跟踪的文件:

git grep -L "foo"

如果你在 .bashrc 中开启了子目录 globbing(shopt -s globstar,参见 这里),你可以在跟踪的文件子集中进行搜索:

git grep -L "foo" -- **/*.cpp

10

实际上,您需要:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep :0\$

9

为了完整起见,以下是ripgrep版本:

rg --files-without-match "pattern"

您可以与文件类型和搜索路径结合使用,例如:

rg --files-without-match -t ruby "frozen_string_literal: true" app/

5

问题

我需要重构一个使用.phtml文件以内联PHP代码写出HTML的大型项目。我想改用Mustache模板。我想找到任何不包含字符串 new Mustache .phtml文件,因为这些文件仍然需要重新编写。

解决方案

find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

说明

管道符之前:

查找

find . 从此目录开始递归查找文件

-iname '*.phtml' 文件名必须包含.phtmli表示不区分大小写)

-exec 'grep -H -E -o -c 'new Mustache' {}' 在每个匹配路径上运行grep命令

grep

-H 总是打印输出行的文件名头。

-E 将模式解释为扩展正则表达式(即强制grep行为像egrep)。

-o 仅打印匹配的行。

-c 仅将所选行的计数写入标准输出。


这将给我一个以.phtml结尾的所有文件路径列表,并显示每个文件中字符串 new Mustache 出现的次数。

$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/orders.phtml:1
./app/MyApp/Customer/View/Account/banking.phtml:1
./app/MyApp/Customer/View/Account/applycomplete.phtml:1
./app/MyApp/Customer/View/Account/catalogue.phtml:1
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

第一个管道 grep :0$ 将此列表过滤,只包括以 :0 结尾的行:

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

第二个管道 sed 's/..$//' 剥离每行的最后两个字符,只留下文件路径。
$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
./app/MyApp/Customer/View/Account/studio.phtml
./app/MyApp/Customer/View/Account/classadd.phtml
./app/MyApp/Customer/View/Account/orders-trade.phtml

5

我在使用

技术方面运气不错。
grep -H -E -o -c "foo" */*/*.ext | grep ext:0

我尝试使用grep -v,但只得到了所有没有"foo"的行。


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