How do I grep for a pattern inside all directories and sub-directories of my Linux server? Is it possible to perform grep recursively? Can you show me some examples to grep for a pattern or a string recursively across multiple directories?
With grep utility we have two arguments which can help you perform grep recursively, from the man page of grep
-r, --recursive Read all files under each directory, recursively, following symbolic links only if they are on the command line. Note that if no file operand is given, grep searches the working directory. This is equivalent to the -d recurse option. -R, --dereference-recursive Read all files under each directory, recursively. Follow all symbolic links, unlike -r.
In this tutorial I will share multiple methods with examples to grep recursively for different scenarios and you can choose the best one which suits your requirement.
1. Grep for string in a file recursively inside all sub-directories
The first scenario which we will cover is where in you have to grep for a string inside all sub-directories. For this we can just use "grep -r" without any additional arguments. The general syntax here would be:
grep [-r|--recursive] [PATH]
Example 1: Search for string "test" inside /tmp/dir recursively
To get all the files which contains "test" string under /tmp/dir, you can use
# grep -r test /tmp/dir/*
OR
# grep -r test /tmp/dir/
OR
Navigate inside the target path
# cd /tmp/dir
And grep for your string
# grep -r test .
All of these commands would search /tmp/dir directory and all sub-directories inside this folder for all the files which contains the word "test" or any matching string with word "test"
test" such as "latest", "testing" etc
2. Grep exact match in a file recursively inside all sub-directories
In this example we will grep for exact pattern instead of all the matching words containing our string. So assuming now we only wish to grep the files which contains "test", but we should not get the output from matching patterns such as "testing", "latest" etc. The general syntax would be:
grep [-r|--recursive] [-w|--word-regexp] [PATH]
Example 1: Grep for exact match recursively
To get all the files which contains exact pattern "test" string under /tmp/dir, you can use
# grep -rw test /tmp/dir/*
OR
# grep -rw test /tmp/dir/
OR
Navigate inside the target path
# cd /tmp/dir
And grep for your string
# grep -rw test .
3. Grep for a string only in pre-defined files
We can also define filename in plain text format or regex which should be searched to grep the provided pattern. For example, I wish to grep for "test" string but only in files which contain "lvm" or "linux" in the filename.
In the below examples we will "Search for test string in file that contains "lvm" and "linux" in the filename". Now we can have a file such as my-lvm.conf, dummy-lvm.conf, store-linux.config so all such files would be eligible when we use "lvm" and "linux" as our regex for filename:
Method 1: Use find with exec
In this example we will use find with exec to search for specific files and grep for our string. Syntax to use with single filename:
find PATH -type f -name <filename> -exec grep [args] [pattern] {} +
Syntax to use with multiple filenames:
find PATH -type f \( -name <filename-1> -o -name <filename-2> \) -exec grep [args] [pattern] {} +
So below example would cover our scenario.
# find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -type f -exec grep -w test {} +

Method 2: using find with xargs
In this example we will combine find with xargs to grep for our string with multiple filenames. Syntax to use with single filename:
find PATH -type f -name <filename> | xargs grep [args] [pattern]
Alternate Method:
find PATH -type f -name <filename> -print0 xargs -0 grep [args] [pattern]
Syntax to use with multiple filenames:
find PATH -type f \( -name <filename-1> -o -name <filename-2> \) | xargs grep [args] [pattern]
So below example can be used to search for all filenames matching "lvm" and "linux" and grep for "test" string
# find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -type f | xargs grep -w test
OR
# find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -type f -print0 | xargs -0 grep -w test

-r or --recursive with grep as by default find will search inside all sub-directories
Method 3: Using grep with --include
We need not be dependent on third tool to search for a string in some specific file, grep itself has an option to search for only provided files.
--include=GLOB
Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).
The syntax to use grep recursively with --include would be:
grep -r --include=GLOB PATTERN PATH
We can use --include multiple times to specify multiple filenames with grep.
# grep --include=*lvm* --include=*linux* -rw test /tmp/dir

4. Grep for string by excluding pre-defined files
Now similar to our last section, we will use find and other tools to exclude certain pre-defined filenames while trying to grep recursively any pattern or string. In the below examples we will "Search for test string in all files except the files that contains lvm and linux in the filename"
Method 1: using find with exec (NOT operator)
In this example we will use find command to exclude certain files while grepping for a string by using NOT (!) operator. The general syntax to use this method would be:
find PATH -type f ! -name <filename-1> ! -name <filename-2> -exec grep [args] [pattern] {} +
In this you can provide multiple files to exclude in your search.
# find /tmp/ ! -name "*linux*" ! -name "*lvm*" -type f -exec grep -w test {} +

As you see we have used NOT (!) operator with some regex to exclude all filenames with "linux" and "lvm" in their name.
Method 2: using find with exec (prune)
We can also use find with exec using "prune" to exclude certain files while grepping for some pattern. The general syntax to use this command would be:
find PATH \( -name <filename-1> -o -name <filename-2> \) -prune -o -type f -exec grep [args] [pattern] {} +
Now we can use this syntax into our example. This will print the file name and the grepped PATTERN
find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -exec grep -w test {} +

OR you can also use grep -H argument to display the filename:
# find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -exec grep -wH test {} \;

If you do not wish to have the filename then you can use:
# find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -exec grep -w test {} \;

Method 3: using find with xargs (NOT operator)
Now similar to find with exec, we can also use the same NOT(!) operator with xargs. The general syntax here would be:
find PATH -type f ! -name <filename-1> ! -name <filename-2> | xargs grep [args] [pattern]
Alternate Method:
find PATH -type f ! -name <filename-1> ! -name <filename-2> -print0 xargs -0 grep [args] [pattern]
Now we will adapt this syntax into our example to grep recursively with find command:
# find /tmp/ ! -name "*linux*" ! -name "*lvm*" -type f -print0 | xargs -0 grep -w test

OR
# find /tmp/ ! -name "*linux*" ! -name "*lvm*" -type f | xargs grep -w test

Method 4: using find with xargs (prune)
Again similar to find with exec, we can use find with xargs combined with prune to exclude certain files. The syntax to achieve this would be:
find PATH -type f \( -name <filename-1> -o -name <filename-2> \) -prune -o -print0 | xargs -0 grep [args] [pattern]
Let us use this syntax in our example:
# find /tmp/ \( -name "*linux*" -o -name "*lvm*" \) -prune -o -type f -print0 | xargs -0 grep -w test

Method 5: Use grep with --exclude
Now all these above methods can be little complicated for beginners so don't worry, we have a supported argument with grep i.e. --exclude=GLOB using which you can exclude certain files when grep is searching for your pattern inside directories and sub-directories. The syntax to use this would be:
grep -r --exclude=GLOB PATTERN PATH
Here you can replace GLOB with the regex or the actual filename of the file which you wish to exclude. You can use --exclude=GLOB multiple times to exclude multiple files
--include and --exclude in a single command with grepSo we can achieve our results using below example without the need of find command:
# grep -r --exclude="*lvm*" --exclude="*linux*" test /tmp/dir/

5. Grep for multiple patterns with recursive search
There can be two possible scenarios here
grepfor multiple strings inside all directories and sub-directoriesgrepfor multiple strings inside same file
Since this tutorial is more about grep recursive, the first question is relative to this tutorial but I will cover both of them.
Example 1: Grep multiple patterns inside directories and sub-directories
With grep we can use -e PATTERN to define multiple patterns at once. The syntax for the same would be:
grep [args] PATH -e PATTERN-1 -e PATTERN-2 ..
For example, I wish to grep for pattern "lvm" and "test" inside all files under /tmp/dir and sub-directories
# grep -rw '/tmp/dir/' -e test -e lvm

Similarly you can add -e PATTERN for as many patterns you have to grep recursively.
Example 2: Grep for multiple strings in single file
We can use the same syntax with -e PATTERN to grep for multiple strings in the same file. Just instead of providing the directory location, provide the name of the file:
# grep -e "lvm" -e "test" lvm.conf
OR
# grep "lvm\|test" lvm.conf
To also print the filename use -H or --with-filename along with grep as shown below:
# grep -H "lvm\|test" lvm.conf
6. Grep recursively for files with symbolic links
By default grep ignores looking into symbolic link files and only searches in text file format. To overcome this, i.e. to make sure grep also looks into symbolic links while searching for string
-R, --dereference-recursive
Read all files under each directory, recursively. Follow all symbolic links, unlike -r.
The syntax to use for this example:
grep -R PATTERN PATH
Example 1: Grep for "test" string under any symlinks and file under /tmp/dir
To achieve this we will use:
# grep -R test /tmp/dir/

Conclusion
In this tutorial we learned that grep itself has an argument to perform recursive search for any pattern or string. You can use -r to grep recursively inside all directories and sub-directories or use -R to also include symlinks in your search (which is excluded with -r). Alternatively we have find command which can be combined with normal grep to search inside all directories and sub-directories, which also allows us to include and exclude certain files and directories from the search.
This tutorial is all about grep but I have also tried to give some overview on usage of find with grep, now find is a very versatile tool, we can add a lot of options to filter your search such as -maxdepth to limit the number of sub-directories to search and many more.
Lastly I hope the steps from the article to perform grep recursively with multiple scenarios and examples on Linux was helpful. So, let me know your suggestions and feedback using the comment section.
You can read more

