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?
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityWhen 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?
Check if your grep
supports -r
option (for recurse):
grep -r <search_string> .
--exclude-dir
to address performance and we have a winner!
grep
on recent FreeBSD and Linux distros support it. And why --exclude-dir
? Didn't you ask to search a whole tree?
Aug 16, 2017 at 16:39
--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.
--exclude-dir
is exclusive to GNU grep
. (-:
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.
grep
implementations catch recursions, I think. Otherwise it depends on what you mean by "tree".
Aug 16, 2017 at 16:51
grep
should do. If the user has symbolic link loops in their directory structure, well, that's the user's problem :-)
/sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...
(-X I like tools babysitting me (unless they provide weird magic they call "AI"). (-;
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' {} '+'
./test2/target.c:1:hello
ack
is great, and a faster version of ack
is ag
(the silver searcher, geoff.greer.fm/ag)
-name '*.log'
It is faster.
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"