Quoting the man page of find (GNU findutils 4.7.0, emphasis mine):
GNU find searches the directory tree rooted at each given starting-point by evaluating the given expression from left to right, according to the rules of precedence (see section PERATORS), 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.
Therefore when find
evaluates <expr1> -and <expr2>
I would expect that <expr2>
is not evaluated unless <expr1>
is true and I rely on that to avoid some error messages, specifically, I do not want find
to test whether a non readable directory is empty. Here is a SCCCE:
mkdir some_dir
chmod 333 some_dir
find * -readable ! -empty -printf "yes" -or -printf "no" -prune
which yields
find: ‘some_dir’: Permission denied
no
Adding, otherwise implicit, -and
and parentheses, the expression evaluated by find
should be equivalent to
( ( -readable -and (! -empty ) ) -and -printf "yes" ) -or ( -printf "no" -and -prune )
Hence, after realising that some_directory
is not readable, find
should forgo the emptiness test and the evaluation of -printf "yes"
. Instead, it should jump to the evaluation of -printf "no"
and finally -prune
. The "Permission denied" in the output suggests it's evaluating -empty
anyway. (Removing ! -empty
from the original expression makes the error go away.)
Using -D tree
to inspect the evaluation tree, I see that the optimised form (edited here for the sake of brevity and clarity) is:
( ( ( ! -empty ) -and -readable ) -and -printf "yes" ) -or ( -printf "no" -and -prune )
according to which -empty
is indeed evaluated and, worse, prior to -readable
which completely screws up the intended logic. I reckon this is a bug. Am I right?
Update: (26-May-2020) A bug report has been submitted and it has been confirmed as a bug by the developers.
In my opinion, this is a bug in findutils' "arm-swapping" optimization, because it fails to consider that -empty
and -xtype
may have the side effect of causing find
to report an error and exit with a non-zero status. I've reported the same issue about -xtype
, which the findutils devs agreed was a bug. It's hard to work around this bug too, because findutils doesn't have a way to turn off this optimization. -O0
is equivalent to -O1
which already applies it.
If you need a workaround, I wrote a drop-in replacement for find
called bfs
: https://github.com/tavianator/bfs. It's fully compatible with all of GNU find's options, and doesn't have this bug.