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

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

369492 次浏览

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

$ grep -L "foo" *

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

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

我有好运气

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

我对grep -v的尝试只是给了我所有没有“foo”的行。

您实际需要:

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

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

相当于你要找的应该是,在ack

ack -L foo

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

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

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

cat file | grep -v "foo"
grep -irnw "filepath" -ve "pattern"

grep -ve "pattern" < file

上面的命令将给我们结果,因为-v找到正在搜索的模式的倒数

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

这些想法是:

  1. 将包含应得字符串的所有文件名转储到txt1.txt.
  2. 将目录中的所有文件名转储到txt2.txt.
  3. 使用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 ">"
    

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

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

打开bug报告

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

由于bug报告进展甚微,下面提到的-L选项不应依赖,只要bug尚未解决。请使用此线程中提出的不同方法。引用bug报告的评论[强调我的]:

有什么更新吗?-L完全忽略文件第一行的匹配项。似乎如果这不会很快修复,国旗应该被完全移除,因为它实际上根本不像广告宣传的那样工作


银搜索者-银(预期功能-见bug报告)

作为grep的强大替代品,您可以使用银搜索者-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

问题

我需要重构一个大型项目,它使用.phtml文件来编写使用内联PHP代码的超文本标记语言。我想使用胡子模板代替。我想找到任何不包含字符串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 像白鹭一样)。

-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

您可以单独使用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

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

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

如果您使用的是git,则会搜索所有跟踪的文件:

git grep -L "foo"

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

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

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

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

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

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

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

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

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

-v,--invert-map选择不匹配的行参见https://stackoverflow.com/a/3548465

也可以将其与vscode一起使用,从终端打开所有文件

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

为完整起见,Ripgrep版本:

rg --files-without-match "pattern"

您可以结合文件类型和搜索路径,例如。

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