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 grep
So 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
grep
for multiple strings inside all directories and sub-directoriesgrep
for 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