find: prune 不忽略指定路径

find: prune 不忽略指定路径

我需要.git从我的find搜索中排除。为了实现这一点,我使用了-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'

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

答案1

我很困惑为什么命令也会打印修剪的目录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

解释了它返回被修剪的目录的原因,而不是在-prune手册页的部分中指出蒂莫的回答,但在该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自动在命令的末尾添加 a,导致该-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页,以防止全世界对此命令产生无休止的混乱。

答案2

页面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),因此会打印该行。

答案3

man页面,

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

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

所以,也许你可以使用:

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

这不会列出.git目录。

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

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

请注意,逗号运算符。

答案4

忽略命令中特定路径的最佳方法是与命令的排除选项一起find使用,如下所述。我在 /var/www/html 中有文件夹。将排除此处的伦敦和东京文件夹以列出其余文件夹中的所有文件。findlsmumbai, dubai,tokyo, delhi, london, rome

ls /var/www/html |grep  -v 'london\|tokyo'  #ls exclude  example is mentioned here.

查找排除提示如下所示:-

find $(ls /var/www/html |grep  -v 'london\|tokyo' ) -type f #run above exclude option with find command as mentioned here. 

相关内容