Search code examples
bashfind

Find -prune argument order affects output list


I have the following directory structure (minimal example):

testdir
testdir/test2
testdir/test2/test2a
testdir/test2/test2a/test2aa
testdir/test1
testdir/test1/test1a
testdir/test1/test1a/test1aa
testdir/test1/test1b
testdir/test1/test1b/test1ba

I would like to find only folders in the depth layer directly below testdir, excluding a certain folder name, here test1. First, the output without excluding test1:

user@xyz:/home/user $ find testdir/* -type d -prune
testdir/test1
testdir/test2

Now, I can exclude test1:

user@xyz:/home/user $ find testdir/* -type d -prune ! -name test1
testdir/test2

However, by changing the order of the -prune argument, subdirectories of test1 are returned:

user@xyz:/home/user $ find testdir/* -type d ! -name test1 -prune
testdir/test1/test1a
testdir/test1/test1b
testdir/test2

Why does the last command return the subdirectories test1a and test1b? I thought the order of the options would not matter, but apparently it does. As far as I understand (not sure about it), -prune prevents find from returning any paths below the patterns matched according to the find options set. But the only match in the first layer below testdir should be test2. Could somebody clarify this for me?


Solution

  • Find -prune argument order affects output list

    That's not especially surprising just on the face of it. The behavior of find is sensitive in general to the relative order of predicates and actions.

    The POSIX specifications for find's behavior are a bit unspecific, but I think GNU find's behavior is pretty typical in the relevant regards, even if that's not actually the find you are using. Its manual page says:

    GNU find searches the directory tree rooted at each given starting-point by evaluating the given expression from left to right [...] until the outcome is known (the left hand side is false for and operations, true for or), at which point find moves on to the next file name.

    (emphasis added).

    Thus, if you put the -name predicate before the -prune action then the -prune is performed only for paths that pass the -name test, but if you put the -name predicate after the -prune then the -name affects only whether paths are printed, not whether they are pruned.