如果您的 grep 具有 -L
(或 --files-without-match
)选项:
$ grep -L "foo" *
您可以单独使用 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
以下命令为我提供了所有不包含模式 foo
的文件:
find . -not -ipath '.*svn*' -exec grep -H -E -o -c "foo" {} \; | grep 0
grep '0$'
也会匹配 10 行的倍数的文件!最后需要 grep ':0$'
来检查行尾是否有明确的 ':0'。然后你只会得到零行匹配的文件。
以下命令不需要 find 使用第二个 grep
过滤掉 svn
文件夹。
grep -rL "foo" ./* | grep -v "\.svn"
如果您使用的是 git,这将搜索所有跟踪的文件:
git grep -L "foo"
如果您打开了 ** 子目录通配符,您可以在跟踪文件的子集中搜索(.bashrc 中的 shopt -s globstar
,请参阅 this):
git grep -L "foo" -- **/*.cpp
您实际上将需要:
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”的行。
问题
我需要重构一个使用 .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'
文件名必须包含 .phtml
(i
使其不区分大小写)
-exec 'grep -H -E -o -c 'new Mustache' {}'
对每个匹配的路径运行 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
当您使用 find 时,您有两个基本选项:在 find 完成搜索后过滤结果或使用一些内置选项,这将阻止 find 考虑那些与某些给定模式匹配的文件和目录。
如果您对大量文件和目录使用前一种方法。您将使用大量 CPU 和 RAM 只是为了将结果传递给第二个进程,而第二个进程又会通过使用大量资源来过滤掉结果。
如果您使用作为 find 参数的 -not 关键字,您将阻止考虑与后面的 -name 或 -regex 参数上的字符串匹配的任何路径,这将更加有效。
find . -not -regex ".*/foo/.*" -regex ".*"
然后,任何未被 -not 过滤掉的路径都将被后续的 -regex 参数捕获。
当 grep 没有 -L 选项(例如 IBM AIX)时的另一种选择,只有 grep 和 shell :
for file in * ; do grep -q 'my_pattern' $file || echo $file ; done
我的 grep 没有任何 -L 选项。我确实找到了解决方法来实现这一点。
这些想法是:
将所有包含应得字符串的文件名转储到 txt1.txt。将目录中的所有文件名转储到一个txt2.txt。用 diff 命令区分 2 个转储文件。 grep 'foo' *.log |切-c1-14 | uniq > txt1.txt grep * *.log |切-c1-14 | uniq > txt2.txt 差异 txt1.txt txt2.txt | grep >"
diff
而不是转储文件名(我认为你用括号括住命令,并且那里也有一个尖括号),如果你的系统支持它,我猜这是问题,因为它不支持 grep -L
find *20161109* -mtime -2|grep -vwE "(TRIGGER)"
您可以在“find”下指定过滤器,在“grep -vwE”下指定排除字符串。如果您还需要过滤修改后的时间,请在 find 下使用 mtime。
打开错误报告
正如@tukan 评论的那样,Ag 有一个关于 -L
/--files-without-matches
标志的开放错误报告:
ggreer/the_silver_searcher: #238 - --files-without-matches 无法正常工作
由于错误报告进展甚微,因此不应依赖下面提到的 -L
选项,只要错误尚未解决。请改用此线程中介绍的不同方法。引用错误报告的评论[强调我的]:
对此有何更新? -L 完全忽略文件第一行的匹配项。似乎如果这不会很快得到解决,则应该完全删除该标志,因为它实际上根本不像宣传的那样工作。
Silver Searcher - Ag(预期功能 - 参见错误报告)
作为 grep
的强大替代品,您可以使用 The Silver Searcher - Ag:
一个类似ack的代码搜索工具,重点是速度。
查看 man ag
,我们发现 -L
或 --files-without-matches
选项:
... 选项 ... -L --files-without-matches 仅打印不包含匹配项的文件的名称。
即,递归从当前目录搜索不匹配 foo
的文件:
ag -L foo
要仅在 当前 目录中搜索与 foo
不匹配的文件,只需为递归指定 --depth=0
:
ag -L foo --depth 0
-L
错误 - github.com/ggreer/the_silver_searcher/issues/238,这有时会失败
这可能对其他人有所帮助。我混合了文件 Go
和 test
文件。但我只需要 .go
个文件。所以我用
ls *.go | grep -v "_test.go"
-v, --invert-match 选择不匹配的行见 https://stackoverflow.com/a/3548465
也可以将它与 vscode 一起使用从终端打开所有文件
code $(ls *.go | grep -v "_test.go")
I have mix of files Go and with test files. But I only need .go files. So I used
我只是添加了这个来帮助我使用的其他人。
为了完整起见,ripgrep 版本:
rg --files-without-match "pattern"
您可以结合文件类型和搜索路径,例如
rg --files-without-match -t ruby "frozen_string_literal: true" app/
grep -irnw "filepath" -ve "pattern"
或者
grep -ve "pattern" < file
上面的命令会给我们结果,因为 -v 找到正在搜索的模式的逆
-l
选项以仅打印文件名;但这仍然会打印包含 any 行但不包含该模式的任何文件的名称。我相信 OP 想要找到不包含任何包含模式的行的文件。
以下命令可以帮助您过滤包含子字符串“foo”的行。
cat file | grep -v "foo"
cat
。
不定期副业成功案例分享
GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git'
来完成 :^)ag -L 'foo'
-rL
而不是-L
来匹配子目录