我不太明白“男人发现”给出的例子,有人能给我一些例子和解释吗?我可以在其中组合正则表达式吗?
更详细的问题是这样的:写一个shell脚本,changeall,它有一个像“changeall [-r | -R]”string1“”string2“这样的接口。它会找到所有后缀为.h,.C的文件,.cc或.cpp并将所有出现的“string1”更改为“string2”.- r是仅保留当前目录或包含subdir的选项。注意:1)对于非递归情况,不允许“ls” ,我们只能使用'find'和'sed'。2)我试过'find -depth'但它不受支持。这就是为什么我想知道'-prune'是否有帮助,但是不明白'男人找'。
EDIT2:我正在做作业,我没有详细提问,因为我想自己完成。既然我已经完成并把它交给我,现在我可以陈述整个问题。此外,我设法在不使用-prune的情况下完成了作业,但无论如何都想学习它。
关于-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]
。
重要笔记:
-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
-type d
谓词。
例如,假设我们想要删除任何以.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
额外提示:如果您使用的是find
的GNU版本,find
的texinfo页面的解释比其联机帮助页更详细(大多数GNU实用程序都是如此)。
请注意,-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
通常我们在linux中做本地的方式和我们的思维方式是从左到右。 所以你会先写下你想要的东西:
find / -name "*.php"
然后你可能点击进入并意识到你从你不希望的目录中获取太多文件。我们排除/ media以避免搜索已安装的驱动器。 您现在应该将以下命令附加到上一个命令:
-print -o -path '/media' -prune
所以最后的命令是:
find / -name "*.php" -print -o -path '/media' -prune
............... | <---包括---> | .................... | < - --------排除---------> |
我认为这种结构更容易,并与正确的方法相关联
添加其他答案中给出的建议(我没有代表创建回复)...
将-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年后,我最近才搜索出这种情况发生的原因。
修剪是一个不递归任何目录切换。
从手册页
如果没有给出-depth,则为true;如果文件是目录,请不要进入该目录。如果给出-depth,则为false;没有效果。
基本上它不会下降到任何子目录。
举个例子:
您有以下目录
如果你运行find -name test2
:
它将返回两个目录
如果你运行find -name test2 -prune
:
它只会返回/ home / test2,因为它不会进入/ home / test2来查找/ home / test2 / test2
我不是这方面的专家(这个页面对http://mywiki.wooledge.org/UsingFind很有帮助)
刚刚注意到-path
是一个完全匹配find
(在这些例子中是.
)之后的字符串/路径的路径,其中-name
匹配所有的基本名称。
find . -path ./.git -prune -o -name file -print
阻止当前目录中的.git目录(作为.
中的发现)
find . -name .git -prune -o -name file -print
以递归方式阻止所有.git子目录。
注意./
非常重要!! -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!
但是最后一个会花费更长的时间,因为它仍在搜索dir1中的所有内容。我想真正的问题是如何在不实际搜索它们的情况下将-or
排除掉不需要的结果。
所以我认为修剪意味着过去的比赛没有得体,但是标记为完成......
http://www.gnu.org/software/findutils/manual/html_mono/find.html“然而,这不是由于'-prune'动作的影响(它只能防止进一步下降,它不能确保我们忽略该项)。相反,这种效果是由于使用'-o' 。由于“或”条件的左侧成功为./src/emacs,因此根本不需要为此特定文件评估右侧(' - print')。“
find
构建了一个文件列表。它将您提供的谓词应用于每个谓词并返回通过的谓词。
-prune
意味着从结果中排除的这个想法对我来说真的很混乱。您可以在不修剪的情况下排除文件:
find -name 'bad_guy' -o -name 'good_guy' -print // good_guy
所有-prune
都会改变搜索的行为。如果当前匹配是一个目录,它会说“嘿find
,你刚刚匹配的那个文件,不要下降到它”。它只是从要搜索的文件列表中删除该树(但不是文件本身)。
它应该被命名为-dont-descend
。