21

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

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

grep -r <search_string> .
6
  • 1
    Yup... I just found stackoverflow.com/questions/16956810/… and that's the answer there too.
    – Dancrumb
    Aug 16 '17 at 16:31
  • add a comment about --exclude-dir to address performance and we have a winner!
    – Dancrumb
    Aug 16 '17 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
    Aug 16 '17 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
    Aug 16 '17 at 16:40
  • In this case I have to add that IIRC --exclude-dir is exclusive to GNU grep. (-:
    – Philippos
    Aug 16 '17 at 16:45
12

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.

6
  • 7
    Use -r instead of -R to skip symlinks when GNU grep is concerned Aug 16 '17 at 16:43
  • 1
    @AFSHIN Why would you not want to follow symlinks?
    – Kusalananda
    Aug 16 '17 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
    Aug 16 '17 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
    Aug 16 '17 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
    Aug 16 '17 at 19:21
12

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.

ack

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' {} '+' 
./test2/target.c:1:hello
5
  • 5
    ack is great, and a faster version of ack is ag (the silver searcher, geoff.greer.fm/ag)
    – cfeduke
    Aug 16 '17 at 20:33
  • 1
    I prefer this with filter like -name '*.log' It is faster.
    – user80158
    Aug 16 '17 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 !) Aug 17 '17 at 22:03
  • A trick is to add /dev/null to the grep to get the filename to appear. Aug 18 '17 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. Aug 18 '17 at 1:12
5

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. :)

0
0

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"
2
  • 1
    backtics aren't good modern practice, they are all but obsolete Aug 17 '17 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
    Aug 17 '17 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.