Differences between revisions 1 and 14 (spanning 13 versions)
Revision 1 as of 2007-05-02 22:52:21
Size: 1828
Editor: redondos
Comment:
Revision 14 as of 2015-03-05 00:24:46
Size: 1828
Editor: izabera
Comment: syntax hl
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[Anchor(faq8)]] <<Anchor(faq8)>>
Line 3: Line 3:
On most recent systems (GNU/Linux/BSD), you would use {{{grep -r pattern .}}} to search all files from the current directory (.) downward. If you are on a typical GNU or BSD system, all you need is one of these:
Line 5: Line 5:
You can use {{{find}}} if your {{{grep}}} lacks -r:
{{{
    find . -type f -exec grep -l "$search" '{}' \;
{{{#!highlight bash
# Recurse and print matching lines (GNU grep):
grep -r -- "$search" .

# Recurse and print only the filenames (GNU grep):
grep -r -l -- "$search" .
Line 10: Line 13:
The {} characters will be replaced with the current file name. If your `grep` lacks a `-r` option, you can [[UsingFind|use find]] to do the recursion:
Line 12: Line 15:
This command is slower than it needs to be, because {{{find}}} will call {{{grep}}} with only one file name, resulting in many {{{grep}}} invocations (one per file). Since {{{grep}}} accepts multiple file names on the command line, {{{find}}} can be instrumented to call it with several file names at once:
{{{
    find . -type f -exec grep -l "$search" '{}' \+
{{{#!highlight bash
# Portable but slow
find . -type f -exec grep -l -- "$search" {} \;
Line 17: Line 20:
The trailing '+' character instructs {{{find}}} to call {{{grep}}} with as many file names as possible, saving processes and resulting in faster execution. This example works for POSIX {{{find}}}, e.g. with Solaris. This command is slower than it needs to be, because {{{find}}} will call {{{grep}}} with only one file name, resulting in many {{{grep}}} invocations (one per file). Since {{{grep}}} accepts multiple file names on the command line, {{{find}}} can be instructed to call it with several file names at once:
Line 19: Line 22:
GNU find uses a helper program called {{{xargs}}} for the same purpose:
{{{
    find . -type f -print0 | xargs -0 grep -l "$search"
{{{#!highlight bash
# Fast, but requires a recent find
find . -type f -exec grep -l -- "$search" {} +
Line 23: Line 26:
The trailing '+' character instructs {{{find}}} to call {{{grep}}} with as many file names as possible, saving processes and resulting in faster execution. This example works for POSIX-2008 {{{find}}}, which ''most'' current operating systems have, but which may not be available on legacy systems.
Line 24: Line 28:
The {{{-print0}}} / {{{-0}}} options ensure that any file name can be processed, even ones containing blanks, TAB characters, or new-lines. Traditional Unix has a helper program called {{{xargs}}} for the same purpose:
Line 26: Line 30:
90% of the time, all you need is: {{{#!highlight bash
# DO NOT USE THIS
find . -type f | xargs grep -l -- "$search"
}}}
However, if your filenames contain spaces, quotes or other metacharacters, this will fail catastrophically. BSD/GNU `xargs` has a `-print0` option:
Line 28: Line 36:
Have grep recurse and print the lines (GNU grep):
{{{
    grep -r "$search" .
{{{#!highlight bash
find . -type f -print0 | xargs -0 grep -l -- "$search"
Line 32: Line 39:
The {{{-print0}}} / {{{-0}}} options ensure that any file name can be processed, even one containing [[BashFAQ/020|blanks, TAB characters, or newlines]].
Line 33: Line 41:
Have grep recurse and print only the names (GNU grep):
{{{
    grep -r -l "$search" .
}}}

The {{{find}}} command can be used to run arbitrary commands on every file in a directory (including sub-directories). Replace {{{grep}}} with the command of your choice. The curly braces {} will be replaced with the current file name in the case above.

(Note that they must be escaped in some shells, but not in ["BASH"].)
----
CategoryShell

How can I recursively search all files for a string?

If you are on a typical GNU or BSD system, all you need is one of these:

   1 # Recurse and print matching lines (GNU grep):
   2 grep -r -- "$search" .
   3 
   4 # Recurse and print only the filenames (GNU grep):
   5 grep -r -l -- "$search" .

If your grep lacks a -r option, you can use find to do the recursion:

   1 # Portable but slow
   2 find . -type f -exec grep -l -- "$search" {} \;

This command is slower than it needs to be, because find will call grep with only one file name, resulting in many grep invocations (one per file). Since grep accepts multiple file names on the command line, find can be instructed to call it with several file names at once:

   1 # Fast, but requires a recent find
   2 find . -type f -exec grep -l -- "$search" {} +

The trailing '+' character instructs find to call grep with as many file names as possible, saving processes and resulting in faster execution. This example works for POSIX-2008 find, which most current operating systems have, but which may not be available on legacy systems.

Traditional Unix has a helper program called xargs for the same purpose:

   1 # DO NOT USE THIS
   2 find . -type f | xargs grep -l -- "$search"

However, if your filenames contain spaces, quotes or other metacharacters, this will fail catastrophically. BSD/GNU xargs has a -print0 option:

   1 find . -type f -print0 | xargs -0 grep -l -- "$search"

The -print0 / -0 options ensure that any file name can be processed, even one containing blanks, TAB characters, or newlines.


CategoryShell

BashFAQ/008 (last edited 2015-03-05 00:24:46 by izabera)