I am using find and getting a list of files I want to grep through. How do I pipe that list to grep?
- 91,316
- 38
- 238
- 232
- 4,908
- 11
- 39
- 53
4 Answers
Well, the generic case that works with any command that writes to stdout is to use xargs, which will let you attach any number of command-line arguments to the end of a command:
$ find … | xargs grep 'search'
Or to embed the command in your grep line with backticks or $(), which will run the command and substitute its output:
$ grep 'search' $(find …)
Note that these commands don't work if the file names contain whitespace, or certain other “weird characters” (\'" for xargs, \[*? for $(find …)).
However, in the specific case of find the ability to execute a program on the given arguments is built-in:
$ find … -exec grep 'search' {} \;
Everything between -exec and ; is the command to execute; {} is replaced with the filename found by find. That will execute a separate grep for each file; since grep can take many filenames and search them all, you can change the ; to + to tell find to pass all the matching filenames to grep at once:
$ find … -exec grep 'search' {} \+
- 91,316
- 38
- 238
- 232
-
3Should be noted that first two forms do not works with filenames containing spaces. – enzotib Sep 07 '11 at 19:09
-
2I prefer `find ... -type f -print0 | xargs -r0 grep 'search' /dev/null`. QED. While `-exec +` is very efficient, it does not exist on all version of find. – Arcege Sep 07 '11 at 19:11
-
Sadly I can not check you correct 3 times. – Tegra Detra Sep 07 '11 at 19:43
-
4I suggest using the `-exec`, rather than than the `xargs`. If you use the `-exec` in [`find`](http://www.folkstalk.com/2011/12/101-examples-of-using-find-command-in.html), it will create only one shell to [grep](http://www.folkstalk.com/2011/12/101-examples-of-using-find-command-in.html) for the content. If you use the `xargs`, it will create two shells: one for the `find` and the other for the `xargs`. – Jan 18 '12 at 18:32
-
2by experiment I find that the `$ find … -exec grep 'search' {} \+` form is *much* the fastest. – gogoud Nov 14 '16 at 10:32
Some versions of grep (e.g. on non-embedded Linux or BSD or Mac OS X) have a -r option to make a recursive search. On OpenBSD, use -R (and there's no --exclude as in the example below). This covers simple combinations of find with grep.
If your implementation doesn't have the -R flag, or if you want fancier file matching criteria, you can use the -exec primary of find to make it execute grep. A few older find implementations don't support -exec … +; on these systems, use a ; instead of the + (this will call grep once per file, so it'll be slower, but otherwise the result will be the same). Note the /dev/null trick to cause grep to show the file name even if it happens to be called on a single file (GNU grep and FreeBSD/NetBSD/OSX grep have a -H option to achieve the same effect).
find . -type f -name '*.o' -prune -o -exec grep 'needle' /dev/null {} +
grep -r --exclude='*.o' 'needle' .
- 807,993
- 194
- 1,674
- 2,175
find ... | while read line; do grep <regex> "$line"; done
- 273
- 2
- 6
-
Although your approach is quite straightforward, please find the time to add a minimum of explanation. Also, please note that this shares the same problem that most of the other answers have in that it relies on [parsing the output of `find`](https://unix.stackexchange.com/questions/321697/why-is-looping-over-finds-output-bad-practice?noredirect=1&lq=1) which should be avoided due to possible problems with special characters in filenames (although that may be repairable depending on the shell used). – AdminBee Sep 18 '20 at 13:13
example :
search for a file which have "Delay" in its name and which have "Create" somewhere inside the found file
find . | grep Delay | xargs grep 'Create'
it should then, if it finds something, display each line where the word 'Create' is written.
- 201
- 3
- 6