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