I'm finding that when I use find's -or operator in combination with -exec, I don't get the result I expect. When searching for .cpp and .h files, the command works as expected if I don't use -exec:

find . -name '*.cpp' -or -name '*.h'

However, when I use -exec, only the .h files seem to be passed:

find . -name '*.cpp' -or -name '*.h' -exec echo '{}' \;

It works fine when I use the more generalized approach for returning the result:

echo $(find . -name '*.cpp' -or -name '*.h')
./file1.cpp ./file1.h ./file2.cpp ./file2.h

However, I'd like to know what I'm doing wrong with -exec, as it's often more convenient. I'm using Mac OSX 10.9, but the same issue occurs in a Cygwin terminal. What's going wrong here? How can I make -exec work the way I want?


That is because your -exe action is tied to the -name "*.h" put parenthesis around the expression and it will work. the default action will -print that is why the initial expression worked.

find . \( -name '*.cpp' -or -name '*.h' \) -exec echo '{}' \;

Also for efficiency if you use | xargs instead of -exec it is a LOT faster with a large result set as it will run a single command with the list as argument instead of an individual call per returned item.

| improve this answer | |
  • Thanks! I had thought that the -exec parameter could only be used once per find invocation. If this were the case, the parens would seem unnecessary. However, it makes sense because the following can also be done: find . -name '*.cpp' -exec echo '{}' \; -or -name '*.h' -exec echo '{}' \; – wonderlr Sep 28 '14 at 18:25
  • 1
    @Rob Worth explaining why your -exe action is tied to the -name "*.h". Namely that -or has a lower order of precedence in find than -a, which is implied in between every juxtaposed set of expressions that isn't specifically separated with another operator. Also, xargs is faster than -exec echo ... \; not -exec echo ... + – user60101 Oct 5 '14 at 7:32

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