How do I perform xargs grep on grep output that has spaces?

Use something like this perhaps (if gnu grep).

grep -r 'content pattern' --include==*.cpp

man grep

--include=GLOB Search only files whose base name matches GLOB (using wildcard matching as described under --exclude)

Also see the options for null delimiters.

-Z, --null Output a zero byte (the ASCII NUL character) instead of the character that normally follows a file name. For example, grep -lZ outputs a zero byte after each file name instead of the usual newline. This option makes the output unambiguous, even in the presence of file names containing unusual characters like newlines. This option can be used with commands like find -print0, perl -0, sort -z, and xargs -0 to process arbitrary file names, even those that contain newline characters.

-z, --null-data Treat the input as a set of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline. Like the -Z or --null option, this option can be used with commands like sort -z to process arbitrary file names.


If you have to jump through a lot of hoops, then the efficiency of xargs is lost anyway. Here is one crude work around:

find . -iname "*.cpp" | grep "<pattern>" | while read -r x; do grep exa "$x"; done

Every time I run into problems with spaces in file names, the answer is double quotes on a variable.


Use find to do all the filename filtering.  Rather than

find . -name "*.cpp" | grep "foo" | xargs grep …

do

find . -name "*.cpp" -name "*foo*" -print0 | xargs -0 grep …

If you want to do something slightly more complicated, like

find . -name "*.cpp" | egrep "foo|bar" | xargs grep …

you can do

find . -name "*.cpp" "(" -name "*foo*" -o -name "*bar*" ")" -print0 | xargs -0 grep …

Note that these should work even for files with newlines in their names.

And, if you need the power of full-blown regular expressions, you can use -regex.