如何查找不包含给定字符串模式的文件?
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
我对@987654322@ 的尝试只是给了我所有没有“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'
文件名必须包含 .phtml
(i
使其不区分大小写)
-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
标志的开放错误报告:
--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】:这可能对其他人有所帮助。我混合了文件Go
和test
文件。但我只需要.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 ofcat
。以上是关于如何查找不包含给定字符串模式的文件?的主要内容,如果未能解决你的问题,请参考以下文章