find: prune 不忽略指定路径

Mar*_*ter 15 bash find

我需要.git从我的find搜索中排除。为了实现这一点,我正在使用-path ./.git -prune开关:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git
Run Code Online (Sandbox Code Playgroud)

然而,即使这跳过了 .git 目录的内容,它也会列出目录本身。当我添加时它有效-path ./.git -prune -o -print -a

find . -path ./.git -prune -o -print -a \( -type f -o -type l -o -type d \) | grep '.git'
Run Code Online (Sandbox Code Playgroud)

为什么这是必要的。我认为这两个命令应该有相同的输出。第二种语法非常难看。

Jer*_*bas 27

我很困惑为什么find命令也会打印修剪后的目录,以及其他一些关于如何-prune工作的复杂细节,但能够通过几个例子弄清楚。

要运行以下示例,请创建以下目录和文件。

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3
Run Code Online (Sandbox Code Playgroud)

要创建此结构:

$ tree

.
??? aa
?   ??? file1
??? bb
?   ??? file3
??? file1
Run Code Online (Sandbox Code Playgroud)

现在使用 find 查找名为aa. 这里没问题。

$ find . -type d -name aa
./aa
Run Code Online (Sandbox Code Playgroud)

查找除 aa 之外的所有目录,我们会得到当前目录.and ./bb,这也是有道理的。

$ find . -type d ! -name aa
.
./bb
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,但是当我们使用时-prune, find 返回我们正在修剪的目录,这最初让我感到困惑,因为我期望它返回所有其他目录而不是被修剪的目录。

$ find . -type d -name aa -prune
./aa
Run Code Online (Sandbox Code Playgroud)

解释了它返回被修剪目录的原因,而不是-pruneTimo's answer 中指出的手册页EXPRESSIONS部分,而是在以下部分:

如果表达式不包含除-prune,? -print对表达式为真的所有文件执行。

这意味着,由于表达式与aa目录名称匹配,因此表达式的计算结果为 true 并打印出来,因为 find-print在整个命令的末尾隐式添加了 a 。-print但是,如果您故意将操作添加-o -print到末尾,它不会添加:

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3
Run Code Online (Sandbox Code Playgroud)

这里 find 命令-print不再添加隐式,因此我们正在修剪的目录 ( aa) 不会被打印。

所以最后,如果我们增加一个条款,对于具有的文件名模式的文件搜索file*-o,那么你必须把-print在像这样的第二句话结束:

find . \( -type d -name aa -prune \) -o \( -type f -name 'file*' -print \)
./file1
./bb/file3
Run Code Online (Sandbox Code Playgroud)

这样做的原因是一样的:如果你没有-print在第二个子句中放一个,那么由于除了动作之外没有-prune动作,find会-print在命令的THE END自动添加一个,导致-prune子句打印修剪目录:

find . \( \( -type d -name aa -prune \) -o \( -type f -name 'file*' \) \) -print
./aa
./file1
./bb/file3
Run Code Online (Sandbox Code Playgroud)

一般情况下,您需要将-print命令放在第二个子句中。如果像原始海报那样将它放在中间,它将无法正常工作,因为被修剪的文件将立即打印出来,并且第二个子句将没有机会选择它想要的文件:

find . \( -type d -name aa -prune -o -print \) -o \( -type f -name 'file*' \)
.
./file1
./bb
./bb/file3
Run Code Online (Sandbox Code Playgroud)

所以不幸的是,原始海报通过将 放在-print错误的位置而导致上面的命令错误。它可能对他的特定情况有效,但在一般情况下不起作用。

有成千上万的人在理解-prune工作原理方面有困难。该find手册页应以防止此命令的无止境的全球混乱更新。


Tim*_*imo 5

man对页面find给出了:

-prune True; if the file is a directory, do not  descend  into  it.  If
      -depth  is  given,  false;  no  effect.  Because -delete implies
      -depth, you cannot usefully use -prune and -delete together.
Run Code Online (Sandbox Code Playgroud)

因此,在第一个示例中,它并非-path ./.git -prune不真实,因此-print不会调用默认操作 ( ),因此会打印该行。