我最喜欢的 BASH 命令之一是:
find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;
它会搜索当前目录及其下所有文件的内容,以查找指定的 SearchString。作为开发人员,这有时会派上用场。
但是,由于我当前的项目和代码库的结构,我想通过不搜索包含“.svn”的目录中或目录中的任何文件,或以“.html”结尾的任何文件,使这个 BASH 命令更加高级
不过 find 的 MAN 页面让我有点困惑。我尝试使用 -prune,结果出现了奇怪的行为。为了只跳过 .html 页面(开始),我尝试了:
find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;
并没有得到我期望的行为。我想我可能没有理解 -prune 的要点。你们能帮我吗?
谢谢
答案1
您可以使用 find 的否定(!)功能来不匹配具有特定名称的文件:
find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;
因此,如果名称以 .html 结尾或在路径中的任何位置包含 .svn,则它将不匹配,因此不会执行 exec。
答案2
我很长时间以来一直遇到同样的问题,并且有几种解决方案可适用于不同情况:
ack-grep
是一种“开发者的grep
”默认情况下跳过版本控制目录和临时文件。该man
页面解释了如何仅搜索特定文件类型以及如何定义你自己的。grep
自己的--exclude
和--exclude-dir
选项可以很容易地用来跳过文件全局变量和单身的目录(遗憾的是,没有目录通配符)。find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ...
应该可以,但是从长远来看,上述选项可能麻烦较少。
答案3
以下find
命令会删除名称为包含 .svn
,虽然它没有进入目录,但打印了修剪的路径名...(-name '*.svn'
是原因!)..
您可以通过以下方式过滤目录名称:grep -d skip
它会默默跳过此类输入的“目录名称”。
使用 GNU grep,你可以使用-H
而不是/dev/null
。 一个小问题:\+
比 快得多\;
,例如,对于 100 万个单行文件,使用\;
它需要4分20秒,使用\+
它只需要1.2秒。
以下方法使用xargs
而不是,并假定您的任何文件中-exec
都没有换行符\n
名称。此处的用法xargs
与 find 的非常相似\+
。
xargs
'\n'
可以通过使用该选项将输入分隔符更改为来传递包含连续空格的文件名-d
。
这不包括以下目录:包含 .svn
并且仅 grep 不以 结尾的文件.html
。
find . \( -name '*.svn*' -prune -o ! -name '*.html' \) |
xargs -d '\n' grep -Hd skip 'SearchString'
答案4
此示例从搜索中排除名称中包含“test”的文件。搜索本身仅针对 XML 文件查找“ProductReplacement”。
find . ! -name '*test*.*' -name '*.xml' -exec grep -i 'ProductReplacement' {} \; -print
您可以使用附加项指定更多排除模式
!-name ‘file_pattern’ 条目。