grep the most used Linux command for searching text patterns in files

Main picture of the post: grep, the most used Linux command for searching text patterns in files

This basic command it’s one of the most used when working with a Linux shell which brings a lot of powerful options to search text like the use of regular expressions. So in this post, it will be explained how to use the grep Linux command through some use cases.

The grep command syntax

The syntax of the grep command is:

grep [OPTION]… PATTERN [FILE]…

As other Linux commands, it has multiple options to leverage the output of grep and most of them can be combined to obtain a more refined results. These are the options that this post will explain in more detail:

-i : ignore case distinctions

–e : use PATTERN for matching

v : select non-matching lines

-w : force PATTERN to match only whole words

-A : print NUM lines of trailing context

-B : print NUM lines of leading context

-r : search PATTERN in subdirectories recursively also

-l : print only names of FILEs containing matches

Case sensitive pattern or text search

If grep is run without any options but with a pattern and a target file, it will get all the lines that contains the pattern passed to the command.

$ grep off text 
coffeemaker
takeoff

This pattern search without any option is case sensitive, se keep in mind this when using the command in this way.

Ignore case pattern or text search

To perform the same pattern search without case sensitive, the “-i” option can be used:

$ grep oFf text
$ grep -i oFf text
coffeemaker
takeoff

The example above shows the execution of grep with and without the “-i” option to ignore case distinctions and the second grep will show results despite that the “F” character doesn’t match in the word found. This means that the command with “-i” option, the pattern could be “OFF”, “Off”, “OfF” and so on but the results will be the same.

Multiple pattern search

With grep command, it is possible to search multiple patterns so either one or another will be a match and showed as a result. In order to do it, the option to use is “-e”:

$ grep -e off -e sand text 
coffeemaker
sandlot
takeoff

The above command with multiple pattern search can be combined with the “-i” option so the following command line will throw the same results as the above one:

$ grep -i -e OFf -e Sand text

Invert match pattern search or select lines that don’t match the pattern

There’s an option to run grep to get all the lines that doesn’t match a pattern by using the the “-v” option:

$ grep -v off text

if you combine with the multiple pattern match with “-e”, you can refine further the text search by getting all the lines from the text that don’t have any of the patterns passed:

$ grep -v -e off -e day -e and text

Again, you can combine the previous example with the “-i” option, to do the same negative matching ignoring case.

Exact pattern match search

Another useful grep option is the “-w” which will change the command to do an exact match. These means that the word matched must have exactly the same characters to be considered as a match for the command:

$ grep -w off text 
$ grep -w coffee text
$ grep -w coffeemaker text 
coffeemaker

The example above, shows that despite “off” and “coffee” is inside the word “coffeemaker” it will not be considered as an exact match so no output is showed by grep. However, if the whole word is provided like in the third command line, then the match will be printed.

Search with a pattern file list

Typing the multiple patterns to look for in the grep command may not be very effective so, there’s an option to get a pattern list from a file to search it in a text. The option related is the “-f”:

$ cat patterns 
life
off
sand
good vibes
$ grep -f patterns text 
lifework
coffeemaker
lifeblood
lifeguard
sandlot
takeoff

Each line from the pattern file will be considered as a single pattern input to the grep command, so the example above will be similar to the next command line:

$ grep -e life -e off -e sand -e "good vibes" text

Search lines that only matches 2 or multiple patterns

Another useful usage to be considered is to combine grep commands to get the lines that match more than one pattern. This is different from using the “-e” option to seek multiple patterns, which will get any line that matches any of pattern. Here’s how you can do it:

$ grep off text
coffeemaker
takeoff
$ grep off text | grep maker
coffeemaker

So, as you can see, the first command will get any line with “off” pattern. But if you want to get the line that has “off” but also “maker” then the second command will do the trick.

Get or print the lines after or before a pattern match

Sometimes, to get the whole line when getting a match is not exactly what you want and you are looking for a section of text right next to the match. The option to do it is the “-A”:

$ grep -A 2 off text 
coffeemaker
lifeblood
fishbowl
--
takeoff
daydream
jetliner

In the previous example, the grep output will show the next 2 lines as well right after the matching line. This could be useful to get sections of text like the content of a XML tag.

The same can be done but with the previous 2 lines right before the matching line with “-B” option:

$ grep -B 2 off text 
lifework
overcoat
coffeemaker
--
pickup
weekday
takeoff

Bear in mind that most of the options commented previously can be combined to get a more refined result, so keep trying combining them until you get the desired results.

Search patterns with regexp

The regular expression is a powerful way to define more complex pattern search and grep allows such patterns. Here are some examples of grep using regular expressions:

$ grep ".off" text 
coffeemaker
takeoff
$ grep "..off" text 
takeoff

As you may appreciate, the first regexp grep command will get the lines matching “off” and whatever single character before it (The wildcard “.”). However, the second one will output the lines matching “off” and any 2 characters before the pattern. So, in this second command, “coffeemaker” is not considered since it has only one character before “off” and the regexp pattern needs 2.

The following command line looks for a word that starts with (The “^” symbol) at least one character and followed by the string “off”:

$ grep ^.off text 
coffeemaker

And in the next command, it will look for a word ended by sequence “lot” (The “$” symbol), preceded by any 2 characters:

$ grep k.lot$ text 
sandlot

In this next example, grep will look for any line starting with lower case “f” followed by any lower case alphabet letter from “a” to “n” and followed by another lower case alphabet letter from “h” to “z”:

$ grep "^f[a-n][h-z]" text
fishbowl
fireworks
fisherman
fishhook

Some of the characters has it’s own way to be declared so, to find out any line recursive

The grep command by default use the Basic Regular Expressions (BRE) to perform the matches, meaning that it will use the meta characters “.”, “*”, “^”, “$” and “[]” for the regexp.

However, by using the “-E” option, grep is able to interpret Extended Regular Expression (ERE) to perform an enhanced pattern match and will use meta characters like “()”, “+”, “{}”, “|”, “?”. So it is possible to make the following searches like:

$ grep -E "^.ish|snow" text
fishbowl
snowbird
fisherman
fishhook
dishpan

The above example is looking for lines starting by either any character followed by “ish” or “snow” in the “text” file.

Another example showed next, will get the lines that has the “ir” string at least once:

$ grep -E "ir{1,}" text
snowbird
fireworks

Print the matched line number

You can get the number of the matched line in the text by running:

$ grep -n son text 
38:grandson
47:spokesperson

This could be useful to get an idea of where is the patterns located in the text.

Search pattern in multiple files recursively

One of the best options that grep brings is the “-r” parameter that allows you to search a pattern in multiple files recursively from the path you are running the command.

Let’s say that we have the following files from the current directory:

$ ls -lR
.:
total 8
drwxrwxr-x. 2 fse fse  25 Apr 17 00:43 com
-rw-rw-r--. 1 fse fse 484 Apr 17 00:43 text
-rw-rw-r--. 1 fse fse  14 Apr 17 01:03 text2

./com:
total 4
-rw-rw-r--. 1 fse fse 482 Apr 17 00:43 anothertext

Then, by running grep in the following way, we can search the pattern “fo” in all the files from the current path:

$ grep -r fo *
com/anothertext:forecast
com/anothertext:footlocker
text:tenfold
text:foreknowledge
text:foreshadow

For each mach found in the files, grep will precede the output with the relative path of the file that the patter was found.

However, the pattern search is not considering the hidden files. To include them in the search, simply skip the file parameter from the command:

$ grep -r fo 
.bashrc:# Uncomment the following line if you don't like systemctl's auto-paging feature:
text:tenfold
text:foreknowledge
text:foreshadow
com/anothertext:forecast
com/anothertext:footlocker
.viminfo:# This viminfo file was generated by Vim 7.4.

This is a pretty useful option from grep for debugging purposes or searching any particular information. It is also possible to combine “-r” with other options described above so the recursive pattern search could be done with a regular expression:

$ grep -r .hou
text:courthouse
com/anothertext:longhouse

If you want to limit the search to all the files from the current path only, then omit the “-r” option and place only a wildcard “*” at the end of the command:

$ grep .bow *
grep: com: Is a directory
text:fishbowl
text2:elbow
text2:rainbow

Get the file name or file path that match the pattern

Sometimes the “-r” option could flood the output with all the matches it finds, making it hard to check which is the file that has a match with the pattern. So, in order to obtain only the file that make the match, the option “-l” could be helpful to obtain only the files that contains the pattern. Here are some examples:

$ grep -rl .bow *
text
text2
$ grep -rl .in *
com/anothertext
text
text2

Match with grep the symbols like dot or wildcard and avoid them interpreted as regular expression

The grep command will work by default with regular expressions and if you try to search the symbols like “.”, “*” or “[” that are interpreted as part of the regexp, the escape character “\” should precede the symbol and the pattern surrounded by double or single quotes. Here are some examples:

$ grep -r "\." 
.bash_logout:# ~/.bash_logout
.bash_profile:# .bash_profile
.bash_profile:if [ -f ~/.bashrc ]; then
.bash_profile:  . ~/.bashrc
.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin
.bashrc:# .bashrc
.bashrc:        . /etc/bashrc
.viminfo:# This viminfo file was generated by Vim 7.4.
.viminfo:       .       2       6
.viminfo:       .       50      0
.viminfo:       .       50      0
$ grep -r "\*" 
.viminfo:*encoding=utf-8
$ grep -r "\[" 
.bash_profile:if [ -f ~/.bashrc ]; then
.bashrc:if [ -f /etc/bashrc ]; then
$ grep -r "\.bashrc \]" 
.bash_profile:if [ -f ~/.bashrc ]; then

Location or full path of grep

The grep command is normally located in /usr/bin/grep:

$ which grep
alias grep='grep --color=auto'
        /usr/bin/grep