For the record, here's the approach that I prefer:
grep pattern $(find . -type f ! -path './test/main.cpp')
By keeping the grep at the beginning of the command, I think this is a little more clear -- plus it doesn't disable grep's color highlighting. In a sense, using find in a command-substitution is just a way of extending/replacing the (limited) file-search subset of grep's functionality.
To me, the find -exec syntax is kind of arcane. One complexity with find -exec is the (sometimes) need for escaping various characters (notably if \; is used under Bash). Just for the purposes of putting things into familiar contexts, the following two commands are basically equivalent:
find . ! -path ./test/main.cpp -type f -exec grep pattern {} +
find . ! -path ./test/main.cpp -type f -print0 |xargs -0 grep pattern
If you want to exclude subdirectories, it may be necessary to use a wildcard. I don't fully understand the schema here -- talk about arcane:
grep pattern $(find . -type f ! -path './test/main.cpp' ! -path './lib/*' )
One further note to generalize find-based solutions for use in scripts: The grep command-line should include the -H/--with-filename option. Otherwise it will change the output formatting under the circumstance that there happens to be only one filename in the search results from find. This is notable because it doesn't appear to be necessary if using grep's native file-search (with the -r option).
...Even better, though, is to include /dev/null as a first file to search. This solves two problems:
- It ensures that if there is one file to search,
grep will think there are two and use the multiple-file output mode.
- It ensures that if there are no files to search,
grep will think there is one file and not hang waiting on stdin.
So the final answer is:
grep pattern /dev/null $(find . -type f ! -path './test/main.cpp')
--exclude-dir). That's why I would like to make grep perform the exclusion natively. – Brent Bradburn May 20 '15 at 15:10