Is there a simpler way to grep all files under a directory?

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?

Asked By: Dancrumb

||

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

grep -r <search_string> .
Answered By: Philippos

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.

Answered By: Kusalananda

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

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. 🙂

Answered By: Petro

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"
Answered By: Rudy
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.