如何在sh中使用'find'的'-prune'选项?

我不太明白“男人找”的例子,谁能给我一些例子和解释? 我可以结合正则expression式吗?


更详细的问题是这样的:编写一个shell脚本changeall,它有一个像“changeall [-r | -R]”string1“”string2“这样的接口,它将find所有具有.h,.C ,.cc或.cpp,并将所有出现的“string1”更改为“string2”。-r是仅保留在当前dir或包括subdir的选项。注意:1)对于非recursion情况,不允许使用“ls” ,我们只能使用'find'和'sed'2)我试过了'find -depth'但是不支持,所以我想知道'-prune'是否可以帮忙,但是不明白'男人find'。


编辑2:我在做任务,我没有提出很详细的问题,因为我想自己完成。 既然我已经把它交了,现在我可以说出整个问题。 另外,我设法完成了任务,而不使用-prune,但仍想学习它。

我发现令人困惑的事情是,这是一个动作(像-print ),而不是testing(像-name )。 它改变了“待办事项”列表, 但总是返回true

使用-prune的一般模式是这样的:

 find [path] [conditions to prune] -prune -o \ [your usual conditions] [actions to perform] 

你几乎总是想在-prune之后立即使用-o ,因为testing的第一部分(包括-prune )将会为你实际需要的东西返回false (即:你不想修剪的东西)。

这是一个例子:

 find . -name .snapshot -prune -o -name '*.foo' -print 

这将find不在“.snapshot”目录下的“* .foo”文件。 在这个例子中, -name .snapshot是“要修剪的东西的testing”,而-name '*.foo' -print是“通常放在path后面的东西”。

重要提示

  1. 如果你所要做的只是打印你可能会用来排除-print操作的结果。 在使用-prune时,您通常希望这样做。

    find的默认行为是如果在最后没有除-prune (具有讽刺意味的)以外的其他操作,则使用-print操作来“和” 整个expression式。 这意味着写这个:

     find . -name .snapshot -prune -o -name '*.foo' # DON'T DO THIS 

    相当于写这个:

     find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS 

    这意味着它也会打印出你正在修剪的目录的名字,这通常不是你想要的。 相反,最好是显式指定-print操作,如果这是你想要的:

     find . -name .snapshot -prune -o -name '*.foo' -print # DO THIS 
  2. 如果您的“常规条件”恰巧匹配也符合您的修剪条件的文件,则这些文件将不会包含在输出中。 解决这个问题的方法是在你的修剪条件中添加一个-type d谓词。

    例如,假设我们想要删除以.git开头的任何目录(这当然是有些人为的 – 通常你只需要删除名为.git东西),但.git ,想要看到所有的文件,包括像.gitignore 。 你可以试试这个:

     find . -name '.git*' -prune -o -type f -print # DON'T DO THIS 

    不会在输出中包含.gitignore 。 这是固定版本:

     find . -type d -name '.git*' -prune -o -type f -print # DO THIS 

额外提示:如果您使用的是GNU版本的find ,那么find的texinfo页面比它的manpage有更详细的解释(对于大多数GNU工具来说)。

请注意,普隆不能像有些人所说的那样阻止进入任何目录。 它可以防止降序到与应用testing相匹配的目录。 也许一些例子会有所帮助(见正则expression式的底部)。 对不起,这太冗长了。

 $ find . -printf "%y %p\n" # print the file type the first time FYI d . f ./test d ./dir1 d ./dir1/test f ./dir1/test/file f ./dir1/test/test d ./dir1/scripts f ./dir1/scripts/myscript.pl f ./dir1/scripts/myscript.sh f ./dir1/scripts/myscript.py d ./dir2 d ./dir2/test f ./dir2/test/file f ./dir2/test/myscript.pl f ./dir2/test/myscript.sh $ find . -name test ./test ./dir1/test ./dir1/test/test ./dir2/test $ find . -prune . $ find . -name test -prune ./test ./dir1/test ./dir2/test $ find . -name test -prune -o -print . ./dir1 ./dir1/scripts ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.sh ./dir1/scripts/myscript.py ./dir2 $ find . -regex ".*/my.*p.$" ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.py ./dir2/test/myscript.pl $ find . -name test -prune -regex ".*/my.*p.$" (no results) $ find . -name test -prune -o -regex ".*/my.*p.$" ./test ./dir1/test ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.py ./dir2/test $ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*" ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.py $ find . -not -regex ".*test.*" . ./dir1 ./dir1/scripts ./dir1/scripts/myscript.pl ./dir1/scripts/myscript.sh ./dir1/scripts/myscript.py ./dir2 

通常情况下,我们在linux上做的事情是我们自己的方式,我们认为是从左到右。
所以你会先写下你要找的东西:

 find / -name "*.php" 

那么你可能会打进来,并意识到你从你不希望的目录得到太多的文件。 让我们排除/媒体,以避免search您的安装的驱动器。
您现在只需将以下命令添加到上一个命令:

 -print -o -path '/media' -prune 

所以最后的命令是:

 find / -name "*.php" -print -o -path '/media' -prune 

…………… | <—包括—> | ……………….. | < – ——–排除———> |

我认为这个结构要容易得多,而且要和正确的方法联系起来

添加到其他答案给出的build议(我没有代表创build答复)…

当将-prune与其他expression式组合在一起时,行为之间会有细微的差别,这取决于使用哪个expression式。

@Laurence Gonsalves的例子会find不在“.snapshot”目录下的“* .foo”文件:

 find . -name .snapshot -prune -o -name '*.foo' -print 

然而,这个略有不同的短手也许会不经意地列出.snapshot目录(以及任何嵌套的.snapshot目录):

 find . -name .snapshot -prune -o -name '*.foo' 

原因是(根据我的系统的手册):

如果给定的expression式不包含任何主要的-exec,-ls,-ok或-print,则给定的expression式可以有效地被replace为:

(given_expression)–print

也就是说,第二个例子相当于input以下内容,从而修改了术语的分组:

 find . \( -name .snapshot -prune -o -name '*.foo' \) -print 

至less在Solaris 5.10上可以看到这一点。 使用了各种口味的* nix大约10年,我最近才find一个为什么发生这种情况的原因。

Prune在任何目录切换时都不会递减。

从手册页

如果没有给出深度,则为真; 如果文件是一个目录,不要下载到它。 如果-depth被给出,则为false; 没有效果。

基本上它不会放入任何子目录。

以这个例子:

你有以下的目录

  • /家/ TEST2
  • /家庭/ TEST2 / TEST2

如果你运行find -name test2

它会返回这两个目录

如果你运行find -name test2 -prune

它将只返回/ home / test2,因为它不会下到/ home / test2中find/ home / test2 / test2

我不是这方面的专家(并且这个网页与http://mywiki.wooledge.org/UsingFind一起非常有帮助);

刚才注意到-path是一个完全匹配的string/path,就像-name (在这个例子中),其中as -name匹配所有的基本名称。

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

阻止当前目录中的.git目录如发现英寸

 find . -name .git -prune -o -name file -print 

以recursion方式阻塞所有的.git子目录。

注意./是非常重要的! -path必须匹配锚定到的path. 或任何后来发现,如果你得到匹配(或“ -o ”的另一边),可能没有被修剪! 我天真地没有意识到这一点,它使我使用-path,当你不想修剪所有具有相同的基本名称的子目录:D

显示包括dir本身在内的所有内容,但不包含冗长的无聊内容:

 find . -print -name dir -prune 

如果你在这里读到所有的好答案,我现在的理解是,以下所有的结果都返回相同的结果:

 find . -path ./dir1\* -prune -o -print find . -path ./dir1 -prune -o -print find . -path ./dir1\* -o -print #look no prune at all! 

但是最后一个将花费更长的时间,因为它仍然searchdir1中的所有内容。 我想真正的问题是如何去实现不需要的结果,而不用实际search它们。

所以我觉得修剪意味着不适合过去的比赛,但将其标记为完成…

http://www.gnu.org/software/findutils/manual/html_mono/find.html “然而,这不是由于”普隆“行动的影响(它只能防止进一步的下降,它不能确保我们忽略了这个项目),而是这个效果是由于使用了'-o',因为“或”条件的左边成功了./src/emacs,所以没有必要去评估右边的项目,手边('印')在这个特定的文件。