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

Posted

技术标签:

【中文标题】如何查找不包含给定字符串模式的文件?【英文标题】:How do I find files that do not contain a given string pattern? 【发布时间】:2010-12-17 09:57:46 【问题描述】:

如何找出当前目录中文件包含单词foo(使用grep)?

【问题讨论】:

【参考方案1】:

如果您的 grep 有 -L(或 --files-without-match)选项:

$ grep -L "foo" *

【讨论】:

正如在别处指出的那样,默认情况下 ack 有助于避免使用 .svn (subversion) 文件。 @GuruM 这可以在 GNU grep 中通过导出变量 GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git' 来完成 :^) 或使用ag的等价物:ag -L 'foo' 如果您想查找名称中没有多个内容的文件怎么办。 grep -L "foo,bar,baz" * ? 像魔术一样工作!提示:使用-rL 而不是-L 来匹配子目录【参考方案2】:

您可以单独使用 grep(无需查找)。

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

【讨论】:

【参考方案3】:

看看ack。它会自动为您排除 .svn,为您提供 Perl 正则表达式,并且是单个 Perl 程序的简单下载。

ack 中应该是您要查找的内容:

ack -L foo

【讨论】:

【参考方案4】:

下面的命令给了我所有不包含foo模式的文件:

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

【讨论】:

您希望将末尾的 grep 0 更改为 grep 0$(否则您会在文件名中包含字符 0 的文件上得到错误匹配)。 @clouseau 基本上是正确的......但是,grep '0$' 也会匹配 10 行的倍数的文件!最后需要grep ':0$' 来检查行尾是否有明确的':0'。那么你只会得到零行匹配的文件。 我使用的 UNIX 没有带有这些选项的 find 或 grep 版本,所以我不得不使用其他 cmets 中建议的“ack”命令。 非常低效,因为 find 必须查找所有文件,包括那些包含“foo”的文件,然后在第二个进程中丢弃它们。对于正在寻找的大量文件将无法正常工作。应该提供使用内置 find 参数的解决方案。【参考方案5】:

以下命令不需要 find 使用第二个 grep 过滤掉 svn 文件夹。

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

【讨论】:

【参考方案6】:

如果你使用 git,这会搜索所有被跟踪的文件:

git grep -L "foo"

如果您打开了 ** 子目录通配符,您可以在跟踪文件的子集中搜索(.bashrc 中的shopt -s globstar,请参阅this):

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

【讨论】:

【参考方案7】:

你实际上需要:

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

【讨论】:

【参考方案8】:

我运气不错

grep -H -E -o -c "foo" */*/*.ext | grep ext:0

我对@9​​87654322@ 的尝试只是给了我所有没有“foo”的行。

【讨论】:

【参考方案9】:

问题

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

解决方案

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

【讨论】:

【参考方案10】:

当您使用 find 时,您有两个基本选项:在 find 完成搜索后过滤掉结果,或者使用一些内置选项来阻止 find 考虑那些与给定模式匹配的文件和目录。

如果您对大量文件和目录使用前一种方法。您将使用大量 CPU 和 RAM 来将结果传递给第二个进程,而第二个进程又会使用大量资源过滤掉结果。

如果您使用作为查找参数的 -not 关键字,您将阻止考虑与后面的 -name 或 -regex 参数上的字符串匹配的任何路径,这将更加有效。

find . -not -regex ".*/foo/.*" -regex ".*"

然后,任何未被 -not 过滤掉的路径都将被后续的 -regex 参数捕获。

【讨论】:

这会搜索不包含特定模式的文件 names,对吗?我认为 OP 的意思是文件 contents 不包含某种模式 嗯,这个问题本身有点含糊,我就是这么解释的。有些人在寻找排除文件名时肯定会找到这个线程。【参考方案11】:

我的 grep 没有任何 -L 选项。我确实找到了解决方法来实现这一点。

这些想法是:

    将所有包含应得字符串的文件名转储到 txt1.txt。 将目录中的所有文件名转储到一个txt2.txt中。

    用diff命令区分2个转储文件。

    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
    grep * *.log | cut -c1-14 | uniq > txt2.txt
    diff txt1.txt txt2.txt | grep ">"
    

【讨论】:

我忘记了命令,但不是转储文件名,您实际上可以在两个输出流之间执行diff(我认为您将命令用括号括起来,并且在某处也有一个尖括号),如果您的系统支持它,我想这是个问题,因为它不支持 grep -L【参考方案12】:

find *20161109* -mtime -2|grep -vwE "(TRIGGER)"

您可以在“find”下指定过滤器,在“grep -vwE”下指定排除字符串。如果您还需要过滤修改后的时间,请在 find 下使用 mtime。

【讨论】:

这似乎向我显示了没有字符串的所有行,OP 只要求提供文件名。【参考方案13】:

打开错误报告

正如@tukan 评论的那样,有一个针对 Ag 的关于 -L/--files-without-matches 标志的开放错误报告:

ggreer/the_silver_searcher: #238 - --files-without-matches does not work properly

由于错误报告几乎没有进展,所以下面提到的-L 选项不应依赖,只要错误尚未解决。请改用此线程中介绍的不同方法。引用错误报告的评论[强调我的]:

这方面有什么更新吗? -L 完全忽略文件第一行的匹配项。似乎如果这个问题不会很快得到解决,应该完全删除该标志,因为它根本不像宣传的那样有效


Silver Searcher - Ag(预期功能 - 参见错误报告)

作为grep 的强大替代品,您可以使用The Silver Searcher - Ag:

类似ack的代码搜索工具,重点是速度。

查看man ag,我们发现-L--files-without-matches 选项:

...

OPTIONS
    ...

    -L --files-without-matches
           Only print the names of files that don´t contain matches.

即,递归从当前目录中搜索与foo 不匹配的文件:

ag -L foo

要仅在 当前 目录中搜索与 foo 不匹配的文件,只需为递归指定 --depth=0

ag -L foo --depth 0

【讨论】:

由于 -L 错误 - github.com/ggreer/the_silver_searcher/issues/238 有时会失败 @tukan 感谢您的提示。我已经更新了答案;选择不删除答案,而是打开有关错误的信息。【参考方案14】:

当 grep 没有 -L 选项时的另一种选择(例如 IBM AIX),只有 grep 和 shell:

for file in * ; do grep -q 'my_pattern' $file || echo $file ; done

【讨论】:

【参考方案15】:

这可能对其他人有所帮助。我混合了文件Gotest 文件。但我只需要.go 文件。所以我用了

ls *.go | grep -v "_test.go"

-v, --invert-match 选择不匹配的行见https://***.com/a/3548465

也可以使用 vscode 来从终端打开所有文件

code $(ls *.go | grep -v "_test.go")

【讨论】:

【参考方案16】:
grep -irnw "filepath" -ve "pattern"

grep -ve "pattern" < file

上面的命令会给我们结果,因为 -v 会找到正在搜索的模式的逆向

【讨论】:

这将打印不包含模式的行。您可以添加-l 选项以仅打印文件名;但这仍然会打印包含不包含模式的 any 行的任何文件的名称。我相信 OP 想要找到不包含任何包含该模式的行的文件。 您提供的命令列出了“文件路径”中的文件及其所有不包含“模式”的行。【参考方案17】:

以下命令可以帮助您过滤包含子字符串“foo”的行。

cat file | grep -v "foo"

【讨论】:

这将打印不匹配的行,而不是在任何行上不包含匹配的文件的名称。雪上加霜,写成useless use of cat

以上是关于如何查找不包含给定字符串模式的文件?的主要内容,如果未能解决你的问题,请参考以下文章

查找包含给定文本的文件

批量查找给定字符串条件的文件

如何使用grep查找多行的模式?

如何在Linux下查找文件内容包含某个特定字符串的文件

在 Hugo 中用字符串按键查找数据

如何在linux中查找包含字符串的行[关闭]