为什么我不能使用 grep find?只有 greping cat 或 find 才有用。据我所知,grep 程序可以看到每个命令运行的上下文。但对于像我这样的新手来说,这是违反直觉的。当使用参数时,grep 可以搜索文件,但当使用管道 ( | ) 时,它就不能。
答案1
该find
命令生成符合搜索条件的路径名列表,在本例中为带扩展名的名称.ebuild
。(但有一个小问题:您需要在通配符周围加上引号,这样 shell 就会将其传递给 find 而不先尝试扩展它。)如果您将其输入到grep
,您所做的只是过滤该名称列表,而不是这些文件的内容。
相比之下,cat $(find ...)
构造使用命令替换(这是其中的$(...)
一部分)将 find 的输出(它生成的路径名列表)粘贴回到命令行作为 的参数cat
,从而将cat
这些文件的内容写入 stdout 和grep
。
做你想做的事情的更简单的方法是使用命令替换将名称grep
直接传递给:
grep RESTRICT $(find /usr/portage -name "e.build")
答案2
为了以更简洁的形式表达 Nicole Hamilton 的命令,您可以将 -exec 标志用于 find 命令。
find /usr/portage -name '*.ebuild' -exec grep RESTRICT {} \;
这会将匹配文件的名称传递给 grep,其中花括号被文件名替换。'\;' 是转义的 ';',用于表示命令的结束。
性能@garyjohn
这是运行 find 命令的不同时间的比较。所有这些测试都是针对 portage 的最新快照执行的(http://distfiles.gentoo.org/snapshots/portage-latest.tar.bz2)。在计时这些测试之前,我运行了“find .”和“grep -Rni . .”,因此我希望磁盘和 RAM 缓存在所有测试中都应该相似。
以下是两个命令的时序:
% time grep RESTRICT $(find . -name "*.ebuild") > /dev/null
grep --color RESTRICT $(find . -name "*.ebuild") > /dev/null 0.05s user 0.13s system 95% cpu 0.192 total
% time find . -name "*.ebuild" -exec grep RESTRICT {} \; > /dev/null
find . -name "*.ebuild" -exec grep RESTRICT {} \; > /dev/null 0.68s user 2.63s system 14% cpu 22.523 total
正如您所看到的,cat 方法比我的示例速度更快,仅花费了大约 5% 的时间。
但是,如果 find 命令返回的文件过多,我们将遇到 shell 对单个命令长度的限制。这将导致命令失败。
% time grep RESTRICT $(find . -name "*") > /dev/null
zsh: argument list too long: grep
grep --color RESTRICT $(find . -name "*") > /dev/null 0.34s user 0.04s system 99% cpu 0.374 tota
要查看您系统上的这个限制,请使用。
getconf ARG_MAX
以下是使用相同 glob 运行的 find。请注意,它需要很长时间才能完成,但它确实成功退出。
% time find . -name "*" -exec grep RESTRICT {} \; > /dev/null
find . -name "*" -exec grep RESTRICT {} \; > /dev/null 2.52s user 11.00s system 12% cpu 1:47.67 total
安全运行此命令的最佳方法是使用 xargs。
% time find . -name "*" -print0 | xargs -0 grep RESTRICT > /dev/null
find . -name "*" -print0 0.16s user 0.29s system 51% cpu 0.886 total
xargs -0 grep RESTRICT > /dev/null 0.33s user 0.59s system 100% cpu 0.915 total
使用 xargs 可以在不到 2 秒的时间内通过 grep 查找整个 portage 树 (~159995 个文件,724M)。