查找:修剪不忽略指定的路径


13

我需要.gitfind搜索中排除。为此,我使用了-path ./.git -prune开关:

$ find . -path ./.git -prune -o \( -type f -o -type l -o -type d \) | grep '.git'
./.git

但是,即使这跳过了.git目录的内容,它也会列出目录本身。当我添加时它起作用-path ./.git -prune -o -print -a

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

为什么这是必要的。我认为这两个命令应该具有相同的输出。第二种语法很丑陋。


4
你需要一个-print,否则隐含-print适用于整个状态
斯特凡Chazelas


Answers:


3

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.

因此,在第一个示例中并非如此,这-path ./.git -prune是不正确的,因此-print不会调用默认操作(),因此将打印该行。


22

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

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

mkdir aa
mkdir bb
touch file1
touch aa/file1
touch bb/file3

要创建此结构:

$ tree

.
├── aa
   └── file1
├── bb
   └── file3
└── file1

现在使用find查找名为的目录aa。没问题

$ find . -type d -name aa
./aa

查找除aa以外的所有目录,我们得到当前目录../bb,这也很有意义。

$ find . -type d ! -name aa
.
./bb

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

$ find . -type d -name aa -prune
./aa

解释了它返回被修剪目录的原因,而不是-pruneTimo的答案所示的手册页部分中说明,而是在该EXPRESSIONS部分中说明:

如果表达式包含比其他任何动作-prune,  -print是在该表达式为true的所有文件执行。

这意味着,由于表达式与aa目录名匹配,因此表达式将求值为true并被打印,因为find -print在整个命令的末尾隐式添加了a 。-print但是,如果您有意-o -print自己将操作添加到结尾,则不会添加:

find . -type d -name aa -prune -o -print
.
./file1
./bb
./bb/file3

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

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

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

起作用的原因是相同的:如果您未-print在第二个子句中放置a ,则由于除了该-prune动作外没有其他动作,find将-print在命令的THE END处自动添加一个,导致该-prune子句打印修剪目录:

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

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

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

因此,很不幸,原始海报将放置-print在错误的位置,从而使上面的命令错误。它可能适用于他的特定情况,但在一般情况下不起作用。

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


我的手册页(Arch Linux,find-4.6.0)说:“如果整个表达式除-prune或-print之外不包含任何动作,则对整个表达式为真的所有文件执行-print。” 但是按照您的描述工作。
x-yuri

0

man页面

要忽略整个目录树,请使用-prune而不是检查树中的每个文件。例如,要跳过目录src / emacs及其下的所有文件和目录,并打印找到的其他文件的名称,请执行以下操作:

find . -path ./src/emacs -prune -o -print

因此,也许您可​​以使用:

find . -path ./.git -prune -o -print

这不会列出.git目录。

要指定文件名,您可以这样:

find . -path ./.git -prune , -name filename

请注意,逗号运算符。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.