grep, originally developed for Unix-based systems, is one of the most widely used command-line utility in Linux boxes.

Its name comes from another similar command in ed tool, i.e., g/re/p which stands for globally search for a regular expression and print matching lines. grep basically searches for a given pattern or regular expression from standard input or file and prints the lines that match the given criteria. It’s often used to filter out unnecessary details while printing just the required information from big log files.

The power of regular expression combines with supported options in grep makes this possible.

Here we will be covering some of the commonly used grep command in different scenarios by sysadmin or developer.

So let’s get started…👨‍💻

grep Command Syntax

grep command expects a pattern and optional arguments along with a file list if used without piping.

$ grep [options] pattern [files]

A simple example is:

$ grep my file.txt
my_file
$

Searching Multiple Files

grep enables you to search for the given pattern not just in one but multiple files. Here’s how you can look for a pattern in multiple files by using * wildcard.

$ sudo grep -i err /var/log/messages*

Output:

$ sudo grep err /var/log/messages*
/var/log/messages:Dec 28 10:36:52 centos7vm kernel: ACPI: Using IOAPIC for interrupt routing
/var/log/messages:Dec 28 10:36:52 centos7vm kernel: ACPI: PCI Interrupt Link [LNKA] (IRQs 5 9 10 *11)
/var/log/messages:Dec 28 10:36:52 centos7vm kernel: ACPI: PCI Interrupt Link [LNKB] (IRQs 5 9 *10 11)
/var/log/messages:Dec 28 10:36:52 centos7vm kernel: ACPI: PCI Interrupt Link [LNKC] (IRQs 5 *9 10 11)
/var/log/messages:Dec 28 10:36:52 centos7vm kernel: ACPI: PCI Interrupt Link [LNKD] (IRQs 5 9 10 *11)
/var/log/messages-20201225:Dec 23 23:01:00 centos7vm kernel: ACPI: Using IOAPIC for interrupt routing
/var/log/messages-20201225:Dec 23 23:01:00 centos7vm kernel: ACPI: PCI Interrupt Link [LNKA] (IRQs 5 9 10 *11)
/var/log/messages-20201225:Dec 23 23:01:00 centos7vm kernel: ACPI: PCI Interrupt Link [LNKB] (IRQs 5 9 *10 11)
/var/log/messages-20201225:Dec 23 23:01:00 centos7vm kernel: ACPI: PCI Interrupt Link [LNKC] (IRQs 5 *9 10 11)
/var/log/messages-20201225:Dec 23 23:01:00 centos7vm kernel: ACPI: PCI Interrupt Link [LNKD] (IRQs 5 9 10 *11)
/var/log/messages-20201225:Dec 23 23:01:00 centos7vm kernel: BERT: Boot Error Record Table support is disabled. Enable it by using bert_enable as kernel parameter.
/var/log/messages-20201227:Dec 27 19:11:18 centos7vm kernel: ACPI: PCI Interrupt Link [LNKA] (IRQs 5 9 10 *11)
/var/log/messages-20201227:Dec 27 19:11:18 centos7vm kernel: ACPI: PCI Interrupt Link [LNKB] (IRQs 5 9 *10 11)
/var/log/messages-20201227:Dec 27 19:11:18 centos7vm kernel: ACPI: PCI Interrupt Link [LNKC] (IRQs 5 *9 10 11)
/var/log/messages-20201227:Dec 27 19:11:18 centos7vm kernel: ACPI: PCI Interrupt Link [LNKD] (IRQs 5 9 10 *11)
/var/log/messages-20201227:Dec 27 19:11:18 centos7vm kernel: BERT: Boot Error Record Table support is disabled. Enable it by using bert_enable as kernel parameter.
/var/log/messages-20201227:Dec 27 19:11:21 centos7vm kernel: [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.
/var/log/messages-20201227:Dec 27 19:11:21 centos7vm kernel: [drm:vmw_host_log [vmwgfx]] *ERROR* Failed to send host log message.
$

You can observe from the above output that the filename is printed first before printing the matching line to indicate where grep found the given pattern.

Case Insensitive Search

grep offers to search a pattern without looking at the case of the pattern. Use -i flag to tell grep to ignore case.

$ grep -i [pattern] [file]

Output:

$ grep -i it text_file.txt
This is a sample text file. It contains
functionality. You can always use grep with any
kind of data but it works best with text data.
It supports numbers like 1, 2, 3 etc. as well as
This is a sample text file. It's repeated two times.
$

Whole Word Search

It’s not always that we want a partial match but instead expect grep to match a complete word only. You can do that with -w flag.

$ grep -w [pattern] [file]

Output:

$ grep -w is text_file.txt
This is a sample text file. It contains
This is a sample text file. It's repeated two times.
$

Check Match Count

Sometimes instead of the actual matched line, we need just the count of successful matches that grep made. We can get this count using -c option.

$ grep -c [pattern] [file]

Output:

$ grep -c is text_file.txt
2
$

Search Sub-directories

It’s often needed to search files not just in the current working directory but also in subdirectories. grep allows you to easily do that with -r flag.

$ grep -r [pattern] *

Output:

$ grep -r Hello *
dir1/file1.txt:Hello One
dir1/file2.txt:Hello Two
dir1/file3.txt:Hello Three
$

As you can observe, grep traverses through each subdirectory inside a current directory and lists the files and lines where a match is found.

Inverse Search

If you want to find something which doesn’t match a given pattern, grep allows doing just that with -v flag.

$ grep -v [pattern] [file]

Output:

$ grep This text_file.txt
This is a sample text file. It contains
This is a sample text file. It's repeated two times.
$ grep -v This text_file.txt
several lines to be used as part of testing grep
functionality. You can always use grep with any
kind of data but it works best with text data.
It supports numbers like 1, 2, 3 etc. as well as
alphabets and special characters like -   * # etc.
$

You can compare the output of grep command on the same pattern and file with and without -v flag. With -v, whichever lines don’t match the pattern gets printed.

Print Line Numbers

grep allows you to print line numbers along with printed lines which makes it easy to know where the line is in the file. Use -n option as shown to get line numbers in output.

$ grep -n [pattern] [file]

Output:

$ grep -n This text_file.txt
1:This is a sample text file. It contains
7:This is a sample text file. It's repeated two times.
$

Limit grep Output

For big files likes logs etc. grep output can be long and you may just need a fixed number of lines in the output instead of matching everything. We can use –m[num] to limit the printed lines by num. Here’s how to use it:

$ grep -m[num] [pattern] [file]

Notice how the use of -m flag affects the output of grep for the same set of conditions in the example below:

$ grep It text_file.txt
This is a sample text file. It contains
It supports numbers like 1, 2, 3 etc. as well as
This is a sample text file. It's repeated two times.
$ grep -m2 It text_file.txt
This is a sample text file. It contains
It supports numbers like 1, 2, 3 etc. as well as
$

Display Additional Lines

Often we need not just the lines which have a matching pattern but some lines above or below it for better context.

It is possible to print a line above or below (or both) a line having a pattern using grep by using -A, -B or -C flags with num value. Here num denotes the number of additional lines to be printed which is just above or below the matched line. This is applicable to all matches that grep finds in the specified file or file list.

$ grep -A[num] [pattern] [file]

OR

$ grep -B[num] [pattern] [file]

OR

$ grep -C[num] [pattern] [file]

Below output shows a normal grep output as well as output with flag -A, -B and -C one by one. Notice how grep interprets the flags and their values and the changes in respective output. With -A1 flag, grep prints 1 line which follows just after the matching line.

Similarly, with -B1 flag, it prints 1 line just before the matching line. With -C1 flag, it prints 1 line which is before and after the matching line.

$ grep numbers text_file.txt
It supports numbers like 1, 2, 3 etc. as well as
$ grep -A1 numbers text_file.txt
It supports numbers like 1, 2, 3 etc. as well as
alphabets and special characters like -   * # etc.
$ grep -B1 numbers text_file.txt
kind of data but it works best with text data.
It supports numbers like 1, 2, 3 etc. as well as
$ grep -C1 numbers text_file.txt
kind of data but it works best with text data.
It supports numbers like 1, 2, 3 etc. as well as
alphabets and special characters like -   * # etc.
$

List File Names

To print just the name of the files where a pattern is found instead of actually matched lines, use -l flag.

$ grep -l [pattern] [file]

Here’s an example run:

$ grep -l su *.txt
file.txt
text_file.txt
$

Print Exact Lines

Sometimes we need to print lines that match exactly with a given pattern, not some part of it. grep allows -x flag to do just that.

$ grep -x [pattern] [file]

In the below example, file.txt contains a line with just one word “support” and as such gets matched by grep with -x flag while ignoring lines that may contain the words “support” along with other text.

$ grep -x support *.txt
file.txt:support
$ 

Match Starting String

Using regular expressions, we can find a string at the start of a line. Here’s how to do it.

$ grep [options] "^[string]" [file]

Example:

$ grep It text_file.txt
This is a sample text file. It contains
It supports numbers like 1, 2, 3 etc. as well as
This is a sample text file. It's repeated two times.
$ grep ^It text_file.txt
It supports numbers like 1, 2, 3 etc. as well as
$

Observe how using ^ character changes the output. ^ indicates the start of the string and grep matched ^It as any line starting with the word It. Enclosing in quotes can help when the pattern contains spaces etc.

Match Ending String

Another common useful regular expression is to match the end of the line pattern.

$ grep [options] "[string]$" [file]

Example:

$ grep "." text_file.txt
This is a sample text file. It contains
functionality. You can always use grep with any
kind of data but it works best with text data.
It supports numbers like 1, 2, 3 etc. as well as
alphabets and special characters like -   * # etc.
This is a sample text file. It's repeated two times.
$ grep ".$" text_file.txt
kind of data but it works best with text data.
alphabets and special characters like -   * # etc.
This is a sample text file. It's repeated two times.
$

We tried to match a . character at the end of the line. Since dot (.) is a special meaning character, we need to escape it with character. Again notice how output varies when we just match . character and when we use $ to instruct grep to match only such lines which end with . (not the ones that may contain it anywhere in between).

Use Pattern File

There may be situations where you have some complex list of patterns that you use often. Instead of writing it down every time, you can specify a list of patterns in a file and use with -f flag. The file should contain one pattern per line.

$ grep -f [pattern_file] [file_to_match]

In our example, we’ve created pattern file names pattern.txt with the below contents:

$ cat pattern.txt
This
It
$

To use it, use -f flag.

$ grep -f pattern.txt text_file.txt
This is a sample text file. It contains
It supports numbers like 1, 2, 3 etc. as well as
This is a sample text file. It's repeated two times.
$

Specify Multiple Patterns

grep allows specifying multiple patterns using -e flag.

$ grep -e [pattern1] -e [pattern2] -e [pattern3]...[file]

Example:

$ grep -e is -e It -e to text_file.txt
This is a sample text file. It contains
several lines to be used as part of testing grep
It supports numbers like 1, 2, 3 etc. as well as
This is a sample text file. It's repeated two times.
$

Specify Extended RegEx

grep also supports Extended Regular Expressions or ERE using -E flag. This is similar to egrep command in Linux.

Using ERE has an advantage when you want to treat meta-characters as is and don’t want to substitute them as strings like grep. This gives you more flexibility in terms of escaping them as we’re required to do in the case of grep. That being said, using -E with grep is equivalent to egrep command.

$ grep -E '[Extended RegEx]' [file]

Here’s one use of ERE where we want to print lines that are not commented or blank. This is especially useful for finding something in big configuration files. I’ve additionally used -v flag to NOT print lines matching the pattern '^(#|$)'.

$ sudo grep -vE '^(#|$)' /etc/ssh/sshd_config
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTHPRIV
AuthorizedKeysFile      .ssh/authorized_keys
PasswordAuthentication yes
ChallengeResponseAuthentication no
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
UsePAM yes
X11Forwarding yes
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
AcceptEnv XMODIFIERS
Subsystem       sftp    /usr/libexec/openssh/sftp-server
$

Conclusion

The above examples is just the tip of the iceberg. grep supports a range of options and can be a very useful tool in the hand of a person who knows how to effectively use it. We can not only use the examples given above but combine them in different ways to get what we need.

Refer to its man page to read more about it.

man grep