Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Search String: Find and Grep

There must be a better / shorter way to do this:

# Find files that contain <string-to-find> in current directory
#   (including sub directories) 
$ find . | xargs grep <string-to-find>

Also, to search only e.g. HTML files:

 # find . | grep html$ | xargs grep <string-to-find>

Thanks beforehand!

like image 991
moey Avatar asked Nov 15 '11 15:11

moey


People also ask

How do I grep to find a string?

The grep command searches through the file, looking for matches to the pattern specified. To use it type grep , then the pattern we're searching for and finally the name of the file (or files) we're searching in. The output is the three lines in the file that contain the letters 'not'.

What is the difference between grep and find?

What is the difference between the grep and find commands? Find is a utility to search for files and directories in the Linux filesystem based on certain criteria (e.g. filename, modify date, size, file type, etc…), grep is a utility to search for patterns in the content of files or in the output of other commands.

Which is faster grep or find?

Is fast grep faster? The grep utility searches text files for regular expressions, but it can search for ordinary strings since these strings are a special case of regular expressions. However, if your regular expressions are in fact simply text strings, fgrep may be much faster than grep .


3 Answers

find . -name \*.html

or, if you want to find files with names matching a regular expression:

find . -regex filename-regex.\*\.html 

or, if you want to search for a regular expression in files with names matching a regular expression

find . -regex filename-regex.\*\.html -exec grep -H string-to-find {} \;

The grep argument -H outputs the name of the file, if that's of interest. If not, you can safely remove it and simply use grep. This will instruct find to execute grep string-to-find filename for each file name it finds, thus avoiding the possibility of the list of arguments being too long, and the need for find to finish executing before it can pass its results to xargs.


To address your examples:

find . | xargs grep <string-to-find>

could be replaced with

find . -exec grep -H string-to-find {} \;

and

find . | grep html$ | xargs grep <string-to-find>

could be replaced with

find . -name \*.html -exec grep -H string-to-find {} \;
like image 127
rid Avatar answered Sep 23 '22 03:09

rid


Not sure what do you mean by better, my first thought was something like this:

grep <string-to-find> $(find -regex .*\.html)

But that's worse because result of the find would be accumulated somewhere in shells memory and then sent as a huge chunk of input arguments

The only imporvement I see too your suggestion is

find -regex .*\.html | xargs grep <string-to-find>

That way find performs all the filtering and you still retain piped processing

like image 28
Ivan Avatar answered Sep 19 '22 03:09

Ivan


If this is going to be a common search utility you're going to utilize, you may want to take a look at ack, which combines both the find and the grep together into this functionality that you're looking for. It has fewer features than grep, though 99% of my searches are suited perfectly by replacing all instances of grep with ack.

Besides the other answers given, I also suggest this construct:

find . -type f -name "*.html" -print|xargs -I FILENAME grep "< string-to-find>" FILENAME
Even better, if the filenames have spaces in them, you can either quote "FILENAME" or pass a null-terminated (instead of newline-terminated) result from find to xargs, and then have xargs strip those out itself:
find . -type f -name "*.html" -print0|xargs -0 -I FILENAME grep "< string-to-find>" FILENAME
                             here --^ and --^

Here, the name FILENAME can actually be anything, but it needs to match both

find . -type f -name "*.html" -print0|xargs -0 -I FILENAME grep "< string-to-find>" FILENAME
                                           here --^                           and --^
Like this:
find . -type f -name "*.html" -print0|xargs -0 -I GRRRR grep "< string-to-find>" GRRR
                                           this --^                       this --^

It's essentially doing the same thing as the {} used within the find statement itself to state "the line of text that this returned". Otherwise, xargs just tacks the results of find to the END of all the rest of the commands you give it (which doesn't help much if you want grep to search inside a file, which is usually specified last on the command-line).

like image 27
OnlineCop Avatar answered Sep 21 '22 03:09

OnlineCop