如何在使用find命令时跳过多个目录

8

我写了一个查找函数,可以在给定路径中的每个文件中搜索字符串,同时跳过我不想要搜索的目录名称列表。我将这个脚本放在我的.bashrc文件中,以便像这样调用:

findTEXTinFILES /path/to/search 'text-to-find'

查找部分功能很好,并且它会对搜索文本进行颜色标记,使其在视觉上突出显示!但是我无法让它跳过使用-prune列出的目录。我已经阅读了所有我能找到的帖子,但没有一个适用于我。我尝试了多种变化也没有成功。所以我有几个问题:

  • 如何跳过多个目录?
  • 如何跳过仅具有部分名称的目录,例如以“--”或“wp-”开头的目录?
  • 您可以在同一脚本中混合使用 -name-path 条件吗?
  • 我还错过了什么吗?

我的服务器是CENTOS 6.9 virtuozzo,使用bash shell。

function findTEXTinFILES {

find "$1" ! \( -name .bash_history -prune \
    -o ! -path tmp -prune \
    -o ! -path short -prune \
    -o ! -path "*/_not_used/*" -prune \
    -o ! -path backups -prune \
    -o ! -path temp_logs -prune \
    -o ! -name .cpan -prune \
    -o ! -name .cpobjcache -prune \
    -o ! -path files_to_compare -prune \
    -o ! -path logs -prune \
    -o ! -path mail -prune  \
    -o ! -path old -prune \
    -o ! -path '--*' -prune \
    -o ! -path 'wp-*' -prune \
    -o ! -path '*copy*' -prune \) \
    -o -name "*" \
    -exec grep $2 -I --color -Hn '$3' '{}' 2>/dev/null \;
}

自从发布这个问题以来,我找到了一个独立的Perl脚本ack,它非常快速并且产生出色的结果。我强烈推荐使用它。链接 - Frank Jance
1个回答

15

find表达式主要由测试操作以及它们之间的运算符组成。它按标准短路计算--也就是一旦结果确定,就无需继续计算所有部分(例如,true或者任何东西计算为true)。

现在请注意,-prune是一个始终返回true的操作。 它可以作用于任何测试的结果。还要注意,默认运算符是-aand)。

因此,最简单的剪枝示例是打印除某个路径下的文件之外的所有文件(例如,在您的示例中是wp-*),如下所示:

find . -path './wp-*' -prune -o -print

对于路径以./wp-开头的文件,执行prune操作,意味着结果为true,可以忽略OR运算符的右侧部分(即文件不会被打印)。需要注意的是,-path匹配相对路径,在这种情况下以.为根目录,因此我们必须写./wp-*而不是wp-*

要剪枝两个路径,只需扩展:

find . -path './wp-*' -prune -o -path ./logs -prune -o -print
如果第一次剪枝操作没有执行(结果为 false),那么就会给第二次机会,如果第二次也不剪枝(结果为 false),那么执行 -print 操作。如果任何一个 -prune 被评估,则不会给 -print 任何机会。
将此应用于您的情况:
find "$1" -name .bash_history -prune \
    -o -path "$1/tmp" -prune \
    -o -path "$1/short" -prune \
    -o -path "$1/*/_not_used/*" -prune \
    -o -path "$1/backups" -prune \
    -o -path "$1/temp_logs" -prune \
    -o -name "$1/.cpan" -prune \
    -o -name "$1/.cpobjcache" -prune \
    -o -path "$1/files_to_compare" -prune \
    -o -path "$1/logs" -prune \
    -o -path "$1/mail" -prune  \
    -o -path "$1/old" -prune \
    -o -path "$1/--*" -prune \
    -o -path "$1/wp-*" -prune \
    -o -path "$1/*copy*" -prune \
    -exec grep $2 -I --color -Hn '$3' '{}' 2>/dev/null \;

为了避免编写依赖于$1的路径,您可以cd "$1"并使用例如find . ... -path ./logs ...


1
很棒的答案。谢谢!+1 针对短路解释。看起来添加当前路径($1) 使其工作。我以前没有看到过这种解释。不过,还有几种情况它不能工作...为了测试,我创建了新目录并添加了要搜索的文件,但脚本没有捕捉到它们,而使用裸的 find 命令却能找到。很奇怪。我还尝试跳过文件名中含有单词“copy”的文件,通过添加 -o -name "$1/*copy*" -prune \ ,但它们仍然在搜索结果中返回。 - Frank Jance
谢谢,不用客气!(如果解决了您的问题,请放心点击接受答案)。 关于您的$1/*copy*搜索——在-name测试中您不能指定路径(只能在-path中)。若要剪枝包含单词“copy”的路径,请使用:-name '*copy*' -prune - randomir

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接