美文网首页
find中的prune

find中的prune

作者: 浙南旧事 | 来源:发表于2020-06-22 20:34 被阅读0次

根据man的说法,prune的作用就是不进入目录。

  1. find

find的简单用法是:

find [path] [expression]

expression主要由options,tests,actions三者组成,这三者又以operators分隔。
expression就是一个表达式,根据operators的优先级,按逻辑运算的方式从左到右执行。options和actions也有返回值,也是表达式中参与逻辑运算的一部分(之前的定式思维没有理解这一点)。

expression的默认operators是"与",即"-a",下面两条命令的含义是一样的:

find ./ -name "2020*" -type d
find ./ -name "2020*" -a -type d

operators的优先级从高到低依次为:
( expr )
! expr
expr1 -a expr2
expr1 -o expr2
expr1, expr2

  1. prune

-prune是一个actions,它的作用就是不进入目录(因此常常与-path一起出现),它本身返回true。

假设有如下目录:

./
./dir0
./dir0/a0.dat
./dir0/a1.txt
./dir0/dir0_0
./dir0/dir0_0/a2.dat
./dir0/dir0_0/a3.txt
./dir0/dir0_1
./dir0/dir0_1/a4.dat
./dir0/dir0_1/a5.txt
./dir1
./dir1/a6.dat
./dir1/a7.txt
./dir1/dir1_0
./dir1/dir1_0/a8.dat
./dir1/dir1_0/a9.txt
./f0.dat
./f1.txt

如果想查找所有的txt文件,但dir0目录下的除外,则可以用如下的命令:

find ./ -path "./dir0" -prune -o -name "*.txt" -print
./dir1/a7.txt
./dir1/dir1_0/a9.txt
./f1.txt

上述命令可以拆解为:
find ./ (expr1 and expr2) or (expr3 and expr4)
其中,
expr1: -path "./dir0"
expr2: -prune
expr3: -name "*.txt"
expr4: -print

执行时,如果遇到./dir0,则expr1返回true,继续执行expr2。expr2是-prune,它的返回值固定是ture,因此(expr1 and expr2)就返回true,or后面的语句不再执行(就不用判断dir0是不是txt,也不会将其打印出来)。整个expression的返回值是true。

注意,man find里有一句话:
If the expression contains no actions other than -prune, -print is performed on all files for which the expression is true.
意思是,如果整个expression为true,而且expression里面除了-prune这个action,就没有其他actions了,则将采用-print这个action,即执行打印动作。

遇到dir0时,虽然整个expression的返回值是true,但这个expression里除了-prune这个action,还有-print这个action(虽然没有执行到,但它确实存在),所以不满足描述的条件,因此也不会把dir0打印出来。

由于-prune的side effect是不进入目录,因此将不进入dir0,其下的所有文件都被跳过。

剩余的情况,expr1将返回false,因此(expr1 and expr2)也返回false,将执行(expr3 and expr4),即遇到txt文件将其打印出来。

  1. 更多用例

如果把上述用例中的-prune去掉,结果将是:

find ./ -path "./dir0" -o -name "*.txt" -print
./dir0/a1.txt
./dir0/dir0_0/a3.txt
./dir0/dir0_1/a5.txt
./dir1/a7.txt
./dir1/dir1_0/a9.txt
./f1.txt

即把所有的txt文件都找出来了,与find ./ -name "*.txt"没有差别。

执行时,遇到dir0,-path "./dir0"返回true,整个expression返回true(但不把dir0打印出来,见上面分析)。
会进入dir0目录查找其下的文件。
-path是严格匹配,因此dir0下的文件并不能让-path "./dir0"返回true,表达式的后半段-name "*.txt" -print也将被执行,即遇到txt文件打印出来。
剩余的情况,当然也是遇到txt文件打印出来。

如果把末尾的-print去掉,结果将是:

find ./ -path "./dir0" -prune -o -name "*.txt"
./dir0
./dir1/a7.txt
./dir1/dir1_0/a9.txt
./f1.txt

与原始的用例相比,把dir0打印出来了。

执行时,遇到dir0,-path "./dir0"返回true,整个expression返回true。由于整个expression除了-prune没有其他action了,将用-print作为默认的action,因此会把dir0打印出来。

不进入dir0,其下的所有文件都被跳过。

剩余的情况,遇到txt时,整个expression返回true,用-print作为默认的action,执行打印动作。

如果再随意改一下:

find ./ -path "./dir0" -o -name "*.txt" -prune -print
./dir0/a1.txt
./dir0/dir0_0/a3.txt
./dir0/dir0_1/a5.txt
./dir1/a7.txt
./dir1/dir1_0/a9.txt
./f1.txt

这个也是把所有的txt文件都找出来了,与find ./ -name "*.txt"没有差别。

执行时,遇到dir0,-path "./dir0"返回true,整个expression返回true(但不把dir0打印出来,见上面分析)。

会进入dir0目录查找其下的文件。表达式后面部分的-prune并没有在这里执行到,所以不能阻止进入dir0目录。
如果其他地方有一个目录名为aaa.txt,则表达式后面部分,会把aaa.txt打印出来,但不会进入aaa.txt查找其子目录和文件。


附带说明一下,find里的-name, -path等语句带的pattern,如果包含通配符(比如"*"),一般要把这个pattern用双引号包起来,否则通配符可能会被shell先解析到,导致结果与预期不符。

相关文章

网友评论

      本文标题:find中的prune

      本文链接:https://www.haomeiwen.com/subject/iqyffktx.html