Searching files and content with find and xargs

Showing all .txt files with the word “foo” in them. Prepended with the filenames.

Usually I use grep only with standard input but in this case we would lose the file path if we did that. So xargs to the rescue! It takes the output of the previous command and add it to the last argument to the next. Beautiful and simple magic! 🔮

find / -name *.txt -print0 | xargs -0 grep -H "foo"

The -type f is saying that we only want to search for regular files.

find . -type f -print0 | xargs -0 grep -H "foo"

Regular expression! Wanted to get some in here because it can be useful to filter the searched files.

find . -regex '.*/[a-z].txt' -print0 | xargs -0 grep -H "foo"

One thing to remember is that find can use different regex dialects. On BSD OS’s (which macOS is a variation of) it by default uses the basic POSIX regular expression and the + doesn’t work there. So you need to enable the extended POSIX regular expression by adding the option -E. Check out regexp types reference.

find -E . -regex '.*/[0-9]+.jpg'

The above should match all files like 1.jpg, 30.jpg or 9999999.jpg for that matter. The + should make the preceding expression match one or more times. It works everywhere! But not on mac 💩. There is no--version or -v or anything to see which version it is. It obviously comes from some BSD version (man find says BSD General Commands Manual). But which is a mystery for me.

Get rid of annoying error output

When you’re not root and search the whole filesystem you will for sure get a lot of permission denied output which can be overwhelming. There’s a trick to get rid of that:

find / -regex '.*/[0-9]+.jpg' 2>/dev/null

As 2 is the Standard error file descriptor, i.e., stderr it will redirect all errors to /dev/null which is a black hole where you never ever come back from if you get in 😱.

Read more about redirections of input/output here: http://mywiki.wooledge.org/BashGuide/InputAndOutput#File_Redirection-1