To complement olivm's helpful answer and address the OP's puzzlement at the need for -o
:
-prune
, as every find
primary (action or test, in GNU speak), returns a Boolean, and that Boolean is always true
in the case of -prune
.
- Without explicit operators, primaries are implicitly connected with
-a
(-and
), which, like its brethren -o
(-or
) performs short-circuiting Boolean logic.
-a
has higher precedence than -o
.
For a summary of all find
concepts, see https://stackoverflow.com/a/29592349/45375
Thus, the accepted answer,
find . -path ./ignored_directory -prune -o -name fileName.txt -print
is equivalent to (parentheses are used to make the evaluation precedence explicit):
find . \( -path ./ignored_directory -a -prune \) \
-o \
\( -name fileName.txt -a -print \)
Since short-circuiting applies, this is evaluated as follows:
- an input path matching
./ignored_directory
causes -prune
to be evaluated; since -prune
always returns true
, short-circuiting prevents the right side of the -o
operator from being evaluated; in effect, nothing happens (the input path is ignored)
- an input path NOT matching
./ignored_directory
, instantly - again due to short-circuiting - continues evaluation on the right side of -o
:
- only if the filename part of the input path matches
fileName.txt
is the -print
primary evaluated; in effect, only input paths whose filename matches fileName.txt
are printed.
Edit: In spite of what I originally claimed here, -print
IS needed on the right-hand side of -o
here; without it, the implied -print
would apply to the entire expression and thus also print for left-hand side matches; see below for background information.
By contrast, let's consider what mistakenly NOT using -o
does:
find . -path ./ignored_directory -prune -name fileName.txt -print
This is equivalent to:
find . -path ./ignored_directory -a -prune -a -name fileName.txt -a -print
This will only print pruned paths (that also match the -name
filter), because the -name
and -print
primaries are (implicitly) connected with logical ANDs;
in this specific case, since ./ignored_directory
cannot also match fileName.txt
, nothing is printed, but if -path
's argument is a glob, it is possible to get output.
A word on find
's implicit use of -print
:
POSIX mandates that if a find
command's expression as a WHOLE does NOT contain either
- output-producing primaries, such as
-print
itself
- primaries that execute something, such as
-exec
and -ok
- (the example primaries given are exhaustive for the POSIX spec. of
find
, but real-world implementations such as GNU find
and BSD find
add others, such as the output-producing -print0
primary, and the executing -execdir
primary)
that -print
be applied implicitly, as if the expression had been specified as:
\( expression \) -print
This is convenient, because it allows you to write commands such as find .
, without needing to append -print
.
However, in certain situations an explicit -print
is needed, as is the case here:
Let's say we didn't specify -print
at the end of the accepted answer:
find . -path ./ignored_directory -prune -o -name fileName.txt
Since there's now no output-producing or executing primary in the expression, it is evaluated as:
find . \( -path ./ignored_directory -prune -o -name fileName.txt \) -print
This will NOT work as intended, as it will print paths if the entire parenthesized expression evaluates to true, which in this case mistakenly includes the pruned directory.
By contrast, by explicitly appending -print
to the -o
branch, paths are only printed if the right-hand side of the -o
expression evaluates to true; using parentheses to make the logic clearer:
find . -path ./ignored_directory -prune -o \( -name fileName.txt -print \)
If, by contrast, the left-hand side is true, only -prune
is executed, which produces no output (and since the overall expression contains a -print
, -print
is NOT implicitly applied).