HowtoForge

How to use grep to search for strings in files on the Linux shell

The GREP command on Linux - an overview

The grep command in Linux is a powerful text-search utility that allows users to search through files or streams of text for specific patterns. It stands for "global regular expression print," and it supports searching by simple text strings and more complex regular expressions. The command is often combined with other commands to filter and refine output. By default, grep returns all lines that contain the pattern. Still, it offers various options to customize the search, such as case sensitivity, counting occurrences, or recursively searching through directories. This makes it an essential tool for system administrators, developers, and anyone working with large sets of data in a Unix-like environment.

The grep command is primarily used to search a text or file for lines that contain a match to the specified words/strings. By default, grep displays the matched lines, and it can be used to search for lines of text that match one or more regular expressions, and it outputs only the matched lines.

Prerequisites

The grep command is part of the base utils of any Linux distribution, so it is preinstalled by default on AlmaLinux, CentOS, Debian, Linux Mint, Ubuntu, RHEL, and RockyLinux.

The basic grep command syntax

The basic grep command syntax is as follows:

grep 'word' filename
grep 'word' file1 file2 file3
grep 'string1 string2'  filename
cat otherfile | grep 'something'
command | grep 'something'
command option1 | grep 'data'
grep --color 'data' fileName

How to use the grep command for searching in a file

In the first example, I will search for the user "tom" in the Linux passwd file. To search the /etc/passwd file for the user "tom", you need to enter the following command:

grep tom /etc/passwd

Given below is the sample Output:

tom:x:1000:1000:tom,,,:/home/tom:/bin/bash

You have the option to instruct grep to ignore word case, i.e., match abc, Abc, ABC, and all possible combinations with the -i option as shown below:

grep -i "tom" /etc/passwd

Recursive use of grep

If you have a bunch of text files in a directory hierarchy, e.g, the Apache configuration files in /etc/apache2/ and you want to find the file where a specific text is defined, then use the -r option of the grep command to do a recursive search. This will perform a recursive search operation trough files for the string "197.167.2.9" (as shown below) in the directory /etc/apache2/ and all its sub-directories:

grep -r "mydomain.com" /etc/apache2/

Alternatively, the following command may be used:

grep -R "mydomain.com" /etc/apache2/

Given below are the Sample outputs for a similar search on an Nginx server:

grep -r "mydomain.com" /etc/nginx/
/etc/nginx/sites-available/mydomain.com.vhost: if ($http_host != "www.mydomain.com") {

Here, you would see the result for mydomain.com on a distinct line preceded by the name of the file (for instance /etc/nginx/sites-available/mydomain.com.vhost) in which it was found. The inclusion of the file names in the output data may be easily suppressed by using the -h option (as explained below): grep -h -R "mydomain.com" /etc/nginx/. Given below is the sample Output:

grep -r "mydomain.com" /etc/nginx/
if ($http_host != "www.mydomain.com") {

Using grep to search only for words

When you are searching for abc, grep will match all sorts of things, viz., kbcabc, abc123, aarfbc35, and lots more combinations without obeying word boundaries. You can compel the grep command to select only those lines that contain matches to form whole words (those that match only abc word), as shown below:

grep -w "abc" file.txt

Example:

Using grep to search two different words

To search for two different words, you must use the egrep command as shown below:

egrep -w 'word1|word2' /path/to/file

Count lines for matched words

The grep command has the ability to report the number of times a particular pattern has been matched for each file using the -c (count) option (as shown below):

grep -c 'word' /path/to/file

In addition, users may use the '-n' option preceding each output line with the number of the line in the text file from which it was obtained (as shown below):

grep -n 'root' /etc/passwd

Given below are the Sample outputs:

1:root:x:0:0:root:/root:/bin/bash

Grep invert match

Users may make use of the -v option to print inverts the match, which means it would match only those lines that do not contain the given word. For instance, print all lines that do not contain the word par by using the following command:

grep -v par /path/to/file

How to list only the names of matching files

You must use the -l option to list file names whose contents mention a particular word, for instance, the word 'primary', using the following command:

grep -l 'primary' *.c

Lastly, you have the option to compel grep to display output in specific colors by using the following command:

grep --color root /etc/passwd

Given below are Sample Outputs:

How to make grep command handle multiple search patterns

There could be situations wherein you might want to search multiple patterns in a given file (or set of files). In such scenarios, you should use the '-e' command-line option that grep provides.

For example, suppose you want to search for words "how", "to", and "forge" in all the text files present in your current working directory, then here's how you can do this:

grep -e how -e to -e forge *.txt

Here's the command in action:

The '-e' command-line option also helps in scenarios wherein the pattern begins with a hyphen (-). For example, if you want to search for, say, "-how", then the following command won't be helpful:

grep -how *.txt

It's when you use the -e command-line option, the command understands what exactly you are trying to search in this case:

grep -e -how *.txt

Here are both commands in action:

How to limit grep output to a particular number of lines

In case you want to limit the grep output to a particular number of lines, you can do that using the '-m' command-line option. For example, suppose you want to search for the word "how" in testfile1.txt which contains the following lines:

But the requirement is for grep to stop searching after 3 lines containing the searched pattern have been found. So, to do this, you can run the following command:

grep "how" -m3 testfile1.txt

Here's the command in action:

Moving on, here is what the command's man page says:

If the input is standard input from a regular file, and NUM matching lines are output, grep ensuresthat the standard input is positioned to just after the last matching line before exiting, regardless of the presence of trailing context lines. This enables a calling process to resume a search.

So for example, if you have a bash script that has a loop, and you want to fetch one match per loop iteration, then using 'grep -m1' will do the needful.

How to make grep obtain patterns from file

If you want, you can also make the grep command obtain patterns from a file. The tool's -f command-line option lets you do this. 

For example, suppose you want to search all the .txt files in the current directory for words "how" and "to", but want to supply these input strings through a file named, say, "input," then here's how you can do this:

grep -f input *.txt

Here's the command in action:

How to make grep display only those lines that completely match the search pattern

Up until now, we have seen that by default grep matches and displays complete lines that contain search patterns. But if the requirement is to make grep only display those lines that completely match the searched pattern, then this can be done using the '-x' command-line option.

For example, suppose testfile1.txt file contains the following lines:

And the pattern you want to search is "how are you?". So to make sure that grep only displays lines that completely match this pattern, use it in the following way:

grep -x "how are you?" *.txt

Here's the command in action:

How to force grep to not display anything in the output

There might be situations wherein you don't need the grep command to produce anything in the output. Instead, you just want to know whether or not a match was found based on the command's exit status. This can be achieved using the -q command-line option.

While the -q option mutes the output, the tool's exit status can be confirmed by the 'echo $?' command. In the case of grep, the command exits with '0' status when it's successful (meaning, a match was found), while it exits with status '1' when no match was found.

The following screenshot shows both the successful and unsuccessful scenarios:

How to make grep display name of files that do not contain search pattern

By default, the grep command displays the name of files containing the search pattern (as well as matched lines). This is quite logical, as that's what expected of this tool. However, there might be cases wherein the requirement could be to get names of those files that do not contain the searched pattern.

This is also possible with grep - the -L options lets you do this. So, for example, to find all those text files in the current directory that does not contain the word "how", you can run the following command:

grep -L "how" *.txt

Here's the command in action:

How to suppress error messages produced by grep

You can force grep to mute any error messages it displays in the output if you want. This can be done using the -s command line option. For example, consider the following scenario in which grep produces error/warning related to the directory it encounters:

So in this kind of scenario, the -s command-line option helps. See below.

So you can see that the error/warning got muted.

How to make grep recursively search directories

As clear from the example used in the previous point, the grep command doesn't do a recursive search by default. To make sure your grep search is recursive, use the -d command-line option and pass the value 'recurse' to it.

grep -d recurse "how" *

Note 1: The directory-related error/warning message we discussed in the previous point can also be muted using the—d option—all you have to do is pass the value 'skip' to it.

Note 2: Use the '--exclude-dir=[DIR]' option to exclude directories matching the pattern DIR from recursive searches.

How to make grep terminate file names with NULL character

As we have already discussed, the -l command-line option of grep is used when you only want the tool to display filenames in the output. For example:

Now, you should know that each name in the above output is separated/terminated by a newline character. Here's how you can verify that:

Redirect the output to a file, and then print the file contents:

So, the output of the cat command confirms the presence of a newline character between the file names.

But as you might already know, the newline character can also be part of a file name. So when dealing with cases where filenames contain a newline and are separated/terminated by newline, it becomes difficult to work on the grep output (especially when accessing the output through a script).

It would be good if the separating/terminating character was not a newline. Well, you'll be glad to know that grep provides a command-line option -Z that ensures filenames are followed by a NULL character and not a newline.

So, in our case, the command becomes:

grep -lZ "how" *.txt

Here's how we confirmed the presence of NULL character:

Following is a related command-line option that you should know:

 -z, --null-data
Treat the input as a set of lines, each terminated by a zero byte (the ASCII NUL character) insteadof a newline. Like the -Z or --null option, this option can be used with commands like sort -z to process arbitrary file names.

How to use GREP to find errors in log files

Grep is the Linux administrator's Swiss army knife when it comes to debugging errors in services. Most Linux services have log files where they report errors. These log files can be huge, and grep is a versatile and fast command to search for, e.g., the IP address of a connecting system, an error string, or the email address of an affected mail user in the mail.log.

Examples:

Search for connections related to a specific email address. Here, 'user@domain.tld' is in the server mail.log file.

grep user@domain.tld /var/log/mail.log

Result:

Aug 22 09:45:10 mail dovecot: pop3-login: Login: user=<user@domain.tld>, method=PLAIN, rip=192.168.0.112, lip=78.46.229.46, mpid=17596, TLS, session=<3uoa5ffQovld3Uep>
Aug 22 09:45:10 mail dovecot: pop3(user@domain.tld)<17596><3uoa5ffQovld3Uep>: Disconnected: Logged out top=0/0, retr=1/6647, del=1/1, size=6630
Aug 22 09:45:10 mail dovecot: pop3-login: Login: user=<user@domain.tld>, method=PLAIN, rip=192.168.0.112, lip=78.46.229.46, mpid=17673, TLS, session=<fIIx6PfQkuBd3Uep>
Aug 22 09:45:10 mail dovecot: pop3(user@domain.tld)<17673><fIIx6PfQkuBd3Uep>: Disconnected: Logged out top=0/0, retr=0/0, del=0/0, size=0
Aug 22 09:45:10 mail dovecot: pop3-login: Login: user=<user@domain.tld>, method=PLAIN, rip=192.168.0.112, lip=78.46.229.46, mpid=17868, TLS, session=<bd5L7ffQPsld3Uep>
Aug 22 09:45:10 mail dovecot: pop3(user@domain.tld)<17868><bd5L7ffQPsld3Uep>: Disconnected: Logged out top=0/0, retr=0/0, del=0/0, size=0
Aug 22 09:45:10 mail dovecot: pop3-login: Login: user=<user@domain.tld>, method=PLAIN, rip=192.168.0.112, lip=78.46.229.46, mpid=17964, TLS, session=<sbpn7vfQevpd3Uep>
Aug 22 09:45:10 mail dovecot: pop3(user@domain.tld)<17964><sbpn7vfQevpd3Uep>: Disconnected: Logged out top=0/0, retr=0/0, del=0/0, size=0
Aug 22 09:45:10 mail postfix/smtpd[6932]: NOQUEUE: reject: RCPT from unknown[1.2.3.4]: 504 5.5.2 <1.2.3.4>: Helo command rejected: need fully-qualified hostname; from=<maillist@mailserver.com> to=<user@domain.tld> proto=ESMTP helo=<1.2.3.4>

To continuously monitor a log file for connections for this email address, combine tail and grep commands like this:

tail -f /var/log/mail.log | grep user@domain.tld

To quit the watch function, press [strg] + c keys.

More GREP command examples

You can find even more examples of using this Linux command in our second GREP command tutorial.

How to use grep to search for strings in files on the Linux shell