1

I have few files under the current directory,

./a.txt
./b.txt
./dir1/c.txt
./dir1/d.txt

When I execute find . -path './dir1' -prune -o -name "*.txt",

as expected, it excludes everything under 'dir1' and prints,

./a.txt
./b.txt
./dir1

now if I switch the sequence of the subexpression and execute find . -name "*.txt" -o -path './dir1' -prune, to my understanding, it should have displayed all the files, as -name "*.txt" subexpression should have matched everything that has .txt extension and just or them with the following test. Therefore 'dir1' directory contents should not have been excluded. But that's doesn't seem to be the case. Displayed result is same as the previous one.

./a.txt
./b.txt
./dir1

what am I missing here?

My system is ubuntu-20.04. I have skim through the find man page and couldn't find any solution. Other sources in the web didn't provide with any satisfactory explanation either.

1

2 Answers 2

0

The -o is not applied in a complete run of find (ie, 'do all the things on the LH side of -o and if nothing is found then do the RH side...)

Instead the -o is file by file which is a big difference. Essentially you have this loop:

  1. Find a file;
  2. apply all the expressions to that file;
  3. IF the overall expression is true, execute the action (which default is print)

The other thing going on here is no combination of -o's or -a's or parenthesis will overcome that -prune has the highest precedence -- if a directory is listed with -prune it is never visited.

If you want to do something along these lines:

find_like . LH_do_first --or RH_do_if_LH_finds_nothing

Then Bash is probably your best bet. Something along these lines:

lh=$(find . -name "*.txt")
cnt=$(awk '/[^[:blank:]]/{cnt++} END {print cnt}' <<<"$lh")
if (( cnt > 0 )); then 
    printf "%s" "$lh"
else
    find . -path "./dir1" -prune
fi    
6
  • in man page, I came across the statement, "... the -prune action itself returns true, so the following -o ensures that the right hand side is evaluated only for those directories which didn't get pruned" source. This gave me impression that absence of -prune in LH means all the files should be evaluated, and return true if either LH or RH is true. "-prune the highest precedence", does that mean -prune in one subexpression excludes files for all other subexpression?
    – nabik
    Commented Jun 25 at 20:49
  • In that same man page: the contents of the pruned directories are not even visited, so their contents are irrelevant. As stated, -prune has the highest precedence.
    – dawg
    Commented Jun 25 at 20:53
  • "-prune the highest precedence", does that mean -prune in one subexpression excludes files for all other subexpression?
    – nabik
    Commented Jun 25 at 20:55
  • thanx. I wish this prune precedence thing was explicitly stated in the manual.
    – nabik
    Commented Jun 25 at 21:05
  • Kinda. Since find is looping over files, and then applies the expressions, the -prune expression is being applied in precedence to what your expectations are. The expressions will shorcircuit on some expressions but not on -prune. It may work as you expect on LH and RH expressions that are not affected by the -prune expression.
    – dawg
    Commented Jun 25 at 21:05
0

You are assuming -prune means "do not show this entry".

Instead, -prune means "do not descend into this directory".

Your top level directory contains the following:

./a.txt
./b.txt
./dir1

If you use -prune when you encounter ./dir1, then find will not descend into it and therefore never look at ./dir1/c.txt or ./dir1/d.txt.

Not the answer you're looking for? Browse other questions tagged or ask your own question.