When I want to search a whole tree for some content, I use

find . -type f -print0 | xargs -0 grep <search_string>

Is there a better way to do this in terms of performance or brevity?

  • 2
    @Downvoter: Happy to improve this question if you can share your concerns.
    – Dancrumb
    Commented Aug 16, 2017 at 16:41
  • 2
    many find versions have xargs built in: find . -type f -exec fgrep <search_string> {} +
    – simpleuser
    Commented Aug 16, 2017 at 22:53

5 Answers 5


Check if your grep supports -r option (for recurse):

grep -r <search_string> .
  • 1
    Yup... I just found stackoverflow.com/questions/16956810/… and that's the answer there too.
    – Dancrumb
    Commented Aug 16, 2017 at 16:31
  • add a comment about --exclude-dir to address performance and we have a winner!
    – Dancrumb
    Commented Aug 16, 2017 at 16:35
  • 1
    Just notice that this is not portable, however grep on recent FreeBSD and Linux distros support it. And why --exclude-dir? Didn't you ask to search a whole tree?
    – Philippos
    Commented Aug 16, 2017 at 16:39
  • Fair point... --exclude-dir is actually handy in my use case (because parts of the subtree are large, but useless) and I did ask about performance... but you're right, it's not necessary.
    – Dancrumb
    Commented Aug 16, 2017 at 16:40
  • In this case I have to add that IIRC --exclude-dir is exclusive to GNU grep. (-:
    – Philippos
    Commented Aug 16, 2017 at 16:45

If you want to recurse down into subdirectories:

grep -R 'pattern' .

The -R option is not a standard option, but is supported by most common grep implementations.

  • 7
    Use -r instead of -R to skip symlinks when GNU grep is concerned Commented Aug 16, 2017 at 16:43
  • 1
    @AFSHIN Why would you not want to follow symlinks?
    – Kusalananda
    Commented Aug 16, 2017 at 16:46
  • 4
    @Kusalananda Recursion? Although current GNU grep implementations catch recursions, I think. Otherwise it depends on what you mean by "tree".
    – Philippos
    Commented Aug 16, 2017 at 16:51
  • 2
    @Philippos IMHO, babysitting the user is not something that a tool like grep should do. If the user has symbolic link loops in their directory structure, well, that's the user's problem :-)
    – Kusalananda
    Commented Aug 16, 2017 at 18:37
  • 3
    @Kusalananda And if the system provided the loop? Never got lost in /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/... (-X I like tools babysitting me (unless they provide weird magic they call "AI"). (-;
    – Philippos
    Commented Aug 16, 2017 at 19:21

A sub optimal answer : Instead of piping the output of find into grep, you could just run

find . -type f -exec grep 'research' {} '+'

and voila, one command instead of two !

explanation :

find . -type f

find all regular files within .

-exec grep 'research'

grep 'research'


in found filename


use one command per all the filenames, not once per filename.

Nb : with ';' it would have been once per filename.

Other than that, if you use that to process source code, you may look into ack, which is made for looking for code bits easily.


Edit :

You can extend that research a little. First, you can use the -name '' switch of find to look for files with specifig naming pattern.

For instance :

  • only files that correspond to logs : -name '*.log'

  • only files that correspond to c headers, but you can't stick with uppercase or lowercase for your filename extensions : -iname *.c

Nb : like for grep and ack, the -i switch means case insensitive in this case.

In that case, grep will show without color and without line numbers.

You can change that with the --color and the -n switches (Color and lines numbers in files respectively).

In the end, you can have something like :

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

for instance

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
  • 5
    ack is great, and a faster version of ack is ag (the silver searcher, geoff.greer.fm/ag)
    – cfeduke
    Commented Aug 16, 2017 at 20:33
  • 1
    I prefer this with filter like -name '*.log' It is faster.
    – user80158
    Commented Aug 16, 2017 at 22:50
  • @cfeduke I haven't tried it, mostly because ag isn't part of default apt repositories on WSL (you gotta work with what you have got !) Commented Aug 17, 2017 at 22:03
  • A trick is to add /dev/null to the grep to get the filename to appear. Commented Aug 18, 2017 at 1:11
  • A trick is to search only for directories and then -exec grep /dev/null {}/* to get all files with single fork/exec per directory. Commented Aug 18, 2017 at 1:12

As noted above -r or -R (depending on desired symlink handling) is a quick option.

However -d <action> can be useful at times.

The nice thing about -d is the skip command, which silences the "grep: directory_name: Is a directory" when you just want to scan the current level.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  

and of course:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  

The -d skip option is REALLY handy inside another script so you don't have to 2> /dev/null. :)


If you are dealing with a lot of files, the grep runs faster if you prune down the files it needs to search through rather than grepping all files in subfolders.

I use this format sometimes:

grep "primary" `find . | grep cpp$`

Find all files in subfolders of . that end in cpp. Then grep those files for "primary".

If you want, you can keep piping those results into further grep calls:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"
  • 1
    backtics aren't good modern practice, they are all but obsolete Commented Aug 17, 2017 at 19:31
  • 1
    This will break if you have files with special characters in their names. I don't know how special they have to be in order to be too special for this to work as-is, but what you are doing is really much the same thing as parsing the output of ls, which is also bad.
    – user
    Commented Aug 17, 2017 at 19:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .