140

I am using find and getting a list of files I want to grep through. How do I pipe that list to grep?

Michael Mrozek
  • 91,316
  • 38
  • 238
  • 232
Tegra Detra
  • 4,908
  • 11
  • 39
  • 53

4 Answers4

178

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' {} \+
Michael Mrozek
  • 91,316
  • 38
  • 238
  • 232
  • 3
    Should be noted that first two forms do not works with filenames containing spaces. – enzotib Sep 07 '11 at 19:09
  • 2
    I 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
  • 4
    I 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
  • 2
    by experiment I find that the `$ find … -exec grep 'search' {} \+` form is *much* the fastest. – gogoud Nov 14 '16 at 10:32
11

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' .
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
3
find ... | while read line; do grep <regex> "$line"; done
vstepaniuk
  • 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
1

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.

serup
  • 201
  • 3
  • 6