If your find
is GNU find
then it supports -true
which always evaluates as true and -false
which always evaluates as false. Then this is what you can do:
# with GNU findfind . -type d -exec echo DIR: \; -false -o -print
The first part is -type d -exec echo DIR: \; -false
, it echoes DIR:
iff the current file is of the type directory. The trailing -false
guarantees this part fails; it will fail even if -type d
evaluates to true. In other words there is no way for this part to succeed, because the only way for it to succeed is to evaluate -type d
to true and -exec echo DIR:
to true and-false
to true. But -false
cannot evaluate to true, ever.
The part preceding -o
always fails, therefore -print
will be evaluated for each and every file, as if -type d
wasn't there.
POSIX-ly you can use -exec false \;
for -false
and -exec true \;
for -true
.
# POSIX-lyfind . -type d -exec echo DIR: \; -exec false \; -o -print
In this case you can avoid spawning false
as an additional process. Use this trick:
# POSIX-lyfind . -type d -exec echo DIR: \; ! -type d -o -print
Again, the part before -o
cannot be true (-type d
and ! -type d
cannot both be true), this guarantees the desired logic. The snippet ! -type d -o
is equivalent to what you used in the question (!
is a portable equivalent of -not
), there is nothing wrong with it.
Note the trick requires you to negate some previous test, while -exec false \;
is universal. -false
is also universal but your find
may or may not support it. If your find
supports -false
and if portability is not an issue, then just use -false -o
as shown at the beginning of this answer; this is the simplest solution.
There is another way to avoid spawning true
and/or false
processes. -name '*'
is a test that always succeeds, so it may be treated as a POSIX equivalent of -true
. Similarly you can use ! -name '*'
for -false
. The downside is -name '*'
kinda obfuscates the code, it does not reveal its purpose; it looks like a remnant of some old -name
test with a meaningful pattern that evolved to *
, now like something that can (and should) be removed from the command. -true
or -exec true \;
are way less confusing.