美文网首页
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