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?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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

grep -r <search_string> .

Method 2

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.

Method 3

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

Method 4

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

Method 5

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"


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments