Shell Foo: Listing All C/C++ Files In a Project, Excluding Build Dir

You’re working on a non-trivial project, with multiple source files, in multiple languages. You want to list all C/C++ source files in the project, recursively, but without getting duplicates from the build dir.

Assuming your C/C++ files are all .h or .cc files, and the build directory is build/ – how would you do it?

Here’s my preferred solution:

$ find . -name \*.h -or -name \*.cc | grep -vE "^\.\/build\/"

Shell-Foo credit for this one: Eyal Fink.

Shell-Foo is a series of fun ways to take advantage of the powers of the shell. In the series, I highlight shell one-liners that I found useful or interesting. Most of the entries should work on bash on Linux, OS X and other UNIX-variants. Some probably work with other shells as well. Your mileage may vary.

Feel free to suggest your own Shell-Foo one-liners!

ShellFoo: Listing all C/C++ files in a project, without the build dir

Explanation

  • find finds all files that match a pattern, recursively from a given directory.
    • The first argument (. in my example) is the starting directory.
    • The -name <pattern> is a name pattern that matches the path relative to the starting directory. \*.h is like *.h – meaning anything that ends with “.h”. The * needs to be escaped so it gets to the find program, avoiding premature expansion.
  • The find command writes to STDOUT all files that matched the pattern. This will include such files under the build directory.
  • grep will filter out those matches under the build directory.
    • -v means invert-grep – so only lines that don’t match the grep pattern are printed.
    • -E means that the pattern is a regular expression. The RegEx is “^./build/”, with . and / escaped. This pattern matches strings that begin (^) with “./build/”.

Alternate solutions

An important downside of the solution I presented is performance. If the build directory is deep and has many C/C++ files, find will spend time traversing it, only to have grep spending time filtering it…

It’s possible to tell find to “prune” the build directory, so it skips it altogether!

$ find . -path ./build -prune -name '*.cc' -or -name '*.h'

I dislike this version, because it confuses me that -prune appears after the pruned pattern… Although this is less typing compared to the other way, so maybe it worths getting used to.

Comments are closed.