Command line wizardry: spaces in file names with find | grep | xargs
Solution 1:
Are you looking for "howdy doody" in the filename, or within the file?
# find files with "howdy doody" in the filename
find * -name "*howdy doody*" -print0 | xargs -0 ...
xargs
is what you need to use to split the null-terminated output from find -print0
. In your example, the echo
is extraneous; don't bother with it.
# find files containing "howdy doody"
find * -print0 | xargs -0 grep -l "howdy doody"
# find files containing "howdy doody" and do further processing
# multiple xargs version
find * -print0 | xargs -0 grep -l "howdy doody" | xargs -i{} do-something "{}"
# "sh -c" version
find * -print0 | xargs -0 -i{} sh -c 'grep -l "howdy doody" "{}" && do-something "{}"'
# notes:
# "sh -c" allows us to run a complex command with a single xargs
# "{}" handles spaces-in-filename
# handles any &&, ||, | command linking
You can also run your command directly from the find
with -exec
. The difference is that find -exec
runs the command once per file found; xargs
adds filenames to the end of the command (up to system limit), so it runs the command fewer times. You can simulate this with xargs -n1
to force xargs
to only run one command per input.
# grep once per file
find * -exec grep -l "howdy doody" {} \; | ...
Solution 2:
You can do it all in one command, using the -exec
argument to find
:
find . -name "*howdy doody*" -exec echo I found file {} hooray \;
The escaped semicolon at the end of the command to execute is required by find
.
Or, if you're looking in the contents of files:
grep -R "howdy doody" *
This will show all text matches, add -l
to the grep to just get a list of files