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

时间:2009-09-28 20:47:01

标签: regex shell find manual

我不太明白'男人发现'给出的例子,有人能给我一些例子和解释吗?我可以在其中组合正则表达式吗?


更详细的问题是这样的:写一个shell脚本,changeall,它有一个像“changeall [-r | -R]”string1“”string2“这样的接口。它会找到所有后缀为.h的文件,。C,.cc或.cpp并将所有出现的“string1”更改为“string2”.- r是仅保留当前目录或包含subdir的选项。注意:1)对于非递归情况,'ls'是不允许的,我们只能使用'find'和'sed'。2)我试过'find -depth'但是它不受支持。这就是为什么我想知道'-prune'是否有帮助,但是不明白例如来自'man find'。


EDIT2:我正在做作业,我没有详细提问,因为我想自己完成。既然我已经完成并把它交给我,现在我可以陈述整个问题。此外,我设法在不使用-prune的情况下完成了作业,但无论如何都想学习它。

10 个答案:

答案 0 :(得分:396)

我发现关于-prune令人困惑的事情是它是一个动作(如-print),而不是一个测试(如-name)。它改变了“待办事项”列表,但始终返回true

使用-prune的一般模式是:

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

您几乎总是希望在-o之后立即-prune(逻辑OR),因为测试的第一部分(包括-prune)将返回 false 用于你真正想要的东西(即:你想要修剪掉的东西)。

以下是一个例子:

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

这将找到不在“.snapshot”目录下的“* .foo”文件。在此示例中,-name .snapshot组成[conditions to prune]-name '*.foo' -print组成[your usual conditions][actions to perform]

重要提示

  1. 如果要打印结果,您可能会习惯忽略-print操作。在使用-prune时,您通常想要这样做。

    如果除了-print(具有讽刺意味)之外没有其他操作,则find的默认行为是“和”整个表达式和-prune操作。这意味着写下这个:

    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开头的任何目录(这无疑是有点人为的 - 通常你只需要删除名为的东西 {{1 }}),但除了想要查看所有文件,包括.git等文件。你可以试试这个:

    .gitignore

    这将在输出中包含find . -name '.git*' -prune -o -type f -print # DON'T DO THIS 。这是固定版本:

    .gitignore
  3. 额外提示:如果您使用的是find . -type d -name '.git*' -prune -o -type f -print # DO THIS 的GNU版本,find的texinfo页面的解释比其联机帮助页更详细(对于大多数GNU实用程序都是如此)。

答案 1 :(得分:26)

请注意-prune不会像某些人所说的那样阻止降级到任何目录。它可以防止降级到与其应用的测试匹配的目录。也许一些例子会有所帮助(请参阅正则表达式示例的底部)。很抱歉这是如此冗长。

$ 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

答案 2 :(得分:23)

通常我们在linux中做事的本地方式和我们思考的方式是从左到右 所以你会先写下你想要的东西:

find / -name "*.php"

然后你可能点击进入并意识到你收到了太多文件 你不希望的目录。 让我们排除/媒体以避免搜索您安装的驱动器 您现在应该将以下命令附加到上一个命令:

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

所以最后的命令是:

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

............... |< ---包括---> | ................... 。|< ----------排除---------> |

我认为这种结构更容易,与正确的方法相关

答案 3 :(得分:9)

添加其他答案中给出的建议(我没有代表创建回复)...

-prune与其他表达式组合时,行为会有细微差别,具体取决于使用的其他表达式。

@Laurence Gonsalves的示例将找到不在“.snapshot”目录下的“* .foo”文件: -

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

然而,这个略有不同的简写,也许是在无意中,也会列出.snapshot目录(以及任何嵌套的.snapshot目录): -

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

原因是(根据我系统的联机帮助页): -

  

如果给定的表达式不包含任何原色-exec,   -ls,-ok或-print,给定的表达式有效地替换为:

     

(given_expression)-print

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

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

至少在Solaris 5.10上已经看到过这种情况。使用各种口味的* nix大约10年后,我最近才搜索出现这种情况的原因。

答案 4 :(得分:3)

Prune是一个不会在任何目录切换时递归。

来自手册页

  

如果没有给出-depth,则为true;         如果文件是目录,请不要进入该目录。     如果给出-depth,则为false;没有效果。

基本上它不会出现在任何子目录中。

举个例子:

您有以下目录

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

如果您运行find -name test2

它将返回两个目录

如果您运行find -name test2 -prune

它只会返回/ home / test2,因为它不会进入/ home / test2来查找/ home / test2 / test2

答案 5 :(得分:2)

我不是这方面的专家(此页面与http://mywiki.wooledge.org/UsingFind

一起非常有用

注意到-path的路径是完全匹配find 之后的字符串/路径(在这些示例中为.),其中{ {1}}匹配所有基本名称。

-name

阻止当前目录中的.git目录,如find . -path ./.git -prune -o -name file -print 中的查找结果)

.

以递归方式阻止所有.git子目录。

注意find . -name .git -prune -o -name file -print 非常重要!! ./必须与锚定到-path 的路径匹配,或者找到之后的任何内容(如果您与其匹配)(来自或.的另一侧')可能没有被修剪! 我天真地没有意识到这一点,当你不想修剪所有具有相同基本名称的子目录时,它让我使用-path很好:D

答案 6 :(得分:1)

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

find . -print -name dir -prune

答案 7 :(得分:0)

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

find . -path ./dir1\*  -prune -o -print

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

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

最后一个会花费更长时间,因为它仍会搜索dir1中的所有内容。我想真正的问题是如何在没有实际搜索结果的情况下-or输出不需要的结果。

所以我认为修剪意味着不要过去不错的比赛,但要把它标记为完成......

http://www.gnu.org/software/findutils/manual/html_mono/find.html &#34;然而,这不是由于'-prune'动作的影响(只能防止进一步下降,它不能确保我们忽略该项目)。相反,这种效果是由于使用'-o'。由于“或”条件的左侧成功为./src/emacs,因此根本不需要为此特定文件计算右侧(' - print')。&#34; < / p>

答案 8 :(得分:0)

find建立文件列表。它将您提供的谓词应用于每个谓词,并返回通过的谓词。

这个-prune意味着从结果中排除的想法确实让我感到困惑。您可以排除没有修剪的文件:

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

所有-prune所做的都是改变搜索的行为。如果当前匹配项是目录,则其显示“嘿find,您刚刚匹配的文件,请不要进入该文件” 。它只是从要搜索的文件列表中删除该树(而不是文件本身)。

应将其命名为-dont-descend

答案 9 :(得分:0)

有很多答案;其中有些过于理论化。我将离开为什么需要修剪一次,所以也许需求优先/示例这样的解释对某人有用:)

问题

我有一个包含约20个节点目录的文件夹,每个目录都有其预期的node_modules目录。

一旦您进入任何项目,就会看到每个../node_modules/module。但是你知道的。几乎每个模块都具有依赖项,因此您正在查看的内容更像projectN/node_modules/moduleX/node_modules/moduleZ...

我不想淹没依赖项为...的列表。

了解-d n / -depth n并不会帮到我,因为我希望每个项目的main / first node_modules目录位于不同的深度,例如:

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

如何获取第一个以第一个node_modules结尾的路径列表,然后移至下一个项目以获取相同的路径?

输入-prune

添加-prune时,您仍然可以进行标准的递归搜索。分析每个“路径”,吐出每个发现,find像好家伙一样不断挖掘。但这是挖掘更多我不想要的node_modules

因此,区别在于,在任何不同的路径中,-prunefind在找到您的商品时停止进一步挖掘该特定途径。就我而言,是node_modules文件夹。