The grep
command is built into many Linux distributions. It runs a utility that searches either for a specific file containing the specified text or for a specific line within a file containing the given characters.
The name "grep" stands for "global regular expression print." Some developers casually say "to grep" something, meaning searching for a specific regular expression in a large set of files.
The command can accept directories with files to search and the text output of other commands, filtering it accordingly.
In this article, we will take a detailed look at using the grep command:
We will break down the grep
command syntax;
Test the functionality of regular expressions;
Try various options while using the command;
Perform searches both within a single file and across entire directories;
Learn how to include and exclude specific files from the search.
The command is structured as follows:
grep [flags] pattern [<path to directory or file>]
First, specify the flags to configure the search and output behavior.
Next, provide a regular expression, which is used to search for text.
As the last argument, enter the path to a file or a directory where the search will be performed. If a directory is specified, the search is performed recursively.
Instead of files and directories, you can also pass the output of another command as input:
another_command | grep [flags] pattern
This helps filter out the most important information from less relevant data during the output from other programs.
Regular expressions are the core of the grep
command. They are essential for creating search patterns. Regular expressions have two levels—Basic Regular Expressions (BRE) and Extended Regular Expressions (ERE). To enable the latter, you need to use the -E
flag.
The nuances of using the grep
utility are best understood through practical examples. We will sequentially review the main methods of searching for strings within files.
Before running any searches, let’s prepare the environment by setting up a few text files that we’ll use with the grep
utility.
First, we’ll create a separate folder to hold the files where we’ll search for matches.
Create a directory:
mkdir files
Then navigate into it:
cd files
Let’s create a couple of files with some text:
nano english.txt
This file will contain an excerpt from Jane Austen’s Pride and Prejudice along with some additional text to demonstrate the search commands:
However little known the feelings or views of such a man may be on his first entering a neighbourhood, this truth is so well fixed in the minds of the surrounding families, that he is considered as the rightful property of some one or other of their daughters.
The surrounding was quite overwhelming
Walking and talking became the main activities of the evening
Additionally, let’s create another text file named sample.txt
:
nano sample.txt
Add the following content:
Line 1: This is the first line.
Line 2: Here we see the second line ending with something interesting.
Line 3: Another normal line follows here.
Line 4: This line is captivating and worth noting.
Line 5: The pattern we seek is right here, at the ending.
Line 6: Yet another normal line to keep the flow.
Line 7: Ending this line with something worth checking.
Line 8: A concluding thought here.
Line 9: This line does not end as the others.
Line 10: Just a regular line here.
Next, let’s add a file that contains some simple JavaScript code:
nano code
Here’s the content:
const number1 = 2;
const number2 = 4;
const sum = number1 + number2;
console.log('The sum of ' + number1 + ' and ' + number2 + ' is ' + sum);
Finally, let’s check the created files:
ls
The console should display:
code english.txt sample.txt
Perfect! These are the files we’ll use to test the functionality of the grep
command.
Let's try to find all instances of the word "the" in the first file:
grep 'the' english.txt
The console will display the found elements, with all occurrences of "the" highlighted in red.
However, there’s an issue—grep
also highlighted parts of words like "other" and "their," which are not standalone articles.
To find only the article "the," we can use the -w
flag. This flag ensures that the search looks for whole words only, without matching subsets of characters within other words:
grep -w 'the' english.txt
Now the terminal will highlight only those instances of "the" that are not part of another word.
We can make the regular expression more complex by adding a special operator. For example, we can find lines that end with a specific set of characters:
grep 'ing$' english.txt
The console will display only those lines that contain the specified matches, with them highlighted in red.
This approach helps refine searches, especially when focusing on precise patterns within text.
You can activate extended regular expressions by specifying the -E
flag. The extended mode adds several new symbols, making the search even more flexible.
+
The preceding character repeats one or more times.
?
The preceding character repeats zero or more times.
{n, m}
The preceding character repeats between n
and m
times.
|
A separator that combines different patterns.
Here’s a small example of using extended regular expressions:
grep -E '[a-z]+ing$' ./*
This command specifies that the string should end with "ing," which must be preceded by one or more lowercase letters.
The output would be something like:
./english.txt:The surrounding was quite overwhelming.
./english.txt:Walking and talking became the main activities of the evening.
Regular expressions, the foundation of the grep
utility, are a versatile formal language used across various programming languages and operating systems.
Therefore, this guide covers only a portion of their capabilities.
The -n
flag can be used to display line numbers alongside the found matches:
grep -n 'ing$' english.txt
The output will be:
4:The surrounding was quite overwhelming.
5:Walking and talking became the main activities of the evening.
The -i
flag allows you to search for matches without considering the case of the characters:
grep -i 'the' english.txt
The output will be:
However little known the feelings or views of such a man may be on his first entering a neighbourhood,
this truth is so well fixed in the minds of the surrounding families,
that he is considered as the rightful property of some one or other of their daughters.
The surrounding was quite overwhelming.
Walking and talking became the main activities of the evening.
If we didn’t use this flag, we would only find the matches with the exact case:
grep 'the' english.txt
However little known the feelings or views of such a man may be on his first entering a neighbourhood,
this truth is so well fixed in the minds of the surrounding families,
that he is considered as the rightful property of some one or other of their daughters.
Walking and talking became the main activities of the evening.
This shows how adjusting flags can refine your search results with grep
.
Sometimes, you need to find only whole words rather than partial matches of specific characters. For this, the -w
flag is used.
We can modify the previous search by using both the -i
and -w
flags simultaneously:
grep -iw 'the' english.txt
The output will contain lines with full matches of the word "the" in any case:
However little known the feelings or views of such a man may be on his first entering a neighbourhood,
this truth is so well fixed in the minds of the surrounding families,
that he is considered as the rightful property of some one or other of their daughters.
The surrounding was quite overwhelming.
Walking and talking became the main activities of the evening.
You can invert the search results, which means it will display only those lines that do not contain the specified matches:
grep -v 'the' english.txt
For clarity, you can include line numbers:
grep -vn 'the' english.txt
The console output will be:
4:The surrounding was quite overwhelming.
As you can see, lines containing the word "the" are excluded from the results.
The line "The surrounding was quite overwhelming." is included because
grep -v
'the' performs a case-sensitive search by default. Since the search pattern 'the' is in lowercase, it does not match the uppercase "The" at the beginning of the sentence. As a result, this line is not excluded from the output.
To exclude lines with any case of "the," you would need to use the
-i
flag along with-v
:
grep -vin 'the' english.txt
This command would then exclude lines containing "The" as well.
You can use multiple regular expressions in a single search by specifying each pattern after the -e
flag:
grep -e 'ing$' -e 'surround' ./*
This command is equivalent to running the two searches sequentially:
grep 'ing$' ./*
grep 'surround' ./*
The combined output will include matches from both patterns.
Let’s move up one level to the root directory:
cd
Now, let’s perform a recursive search in the root directory:
grep -r 'ing$' ./
The grep command will find matches in the directory one level down—in the folder containing text files. The output will be as follows:
./files/english.txt:The surrounding was quite overwhelming.
./files/english.txt:Walking and talking became the main activities of the evening.
Note the file path in the results; it now includes the subdirectory's name.
Let’s navigate back to the folder with the files:
cd files
In some cases, it’s important to extract not only the line with the matching pattern but also the lines surrounding it. This helps to understand the context better.
Using the -A
flag, you can specify the number of lines to display AFTER the line with the found match. For example, let's display one line after each match of lines ending with "ending":
grep -A1 'ending' sample.txt
The output will be:
Line 2: Here we see the second line ending with something interesting.
Line 3: Another normal line follows here.
--
Line 5: The pattern we seek is right here, at the ending.
Line 6: Yet another normal line to keep the flow.
Using the -B
flag, you can specify the number of lines to display BEFORE the line with the found match:
grep -B1 'ending' sample.txt
The output will be:
Line 1: This is the first line.
Line 2: Here we see the second line ending with something interesting.
--
Line 4: This line is captivating and worth noting.
Line 5: The pattern we seek is right here, at the ending.
Using the -C
flag, you can specify the number of lines to display both BEFORE and AFTER the line with the found match:
grep -C1 'ending' sample.txt
The output will be:
Line 1: This is the first line.
Line 2: Here we see the second line ending with something interesting.
Line 3: Another normal line follows here.
Line 4: This line is captivating and worth noting.
Line 5: The pattern we seek is right here, at the ending.
Line 6: Yet another normal line to keep the flow.
The -c
flag allows you to display only the number of matches instead of showing each matching line:
grep -c 'ing$' ./*
The console output will be:
./code:0
./english.txt:2
./sample.txt:4
As you can see, even the absence of matches is displayed in the terminal. In this case, there are three matches in the english.txt file and three in the sample.txt file, while no matches are found in code.
You can limit the output to a specific number of matching lines using the -m
flag. The number of lines is specified immediately after the flag without a space:
grep -m1 'ing$' ./*
Instead of displaying all matches, the console will show only the first occurrence:
./english.txt:The surrounding was quite overwhelming.
./sample.txt:Line 2: Here we see the second line ending with something interesting.
This allows you to shorten the output, displaying only the specified number of matches, which can be useful when working with large datasets.
To search across multiple directories, you can specify a pattern that includes the possible paths of the files you're looking for:
grep 'su' ./*
The terminal will display combined output with matching lines from multiple files:
./code:const sum = number1 + number2;
./code:console.log('The sum of ' + number1 + ' and ' + number2 + ' is ' + sum);
./english.txt:However little known the feelings or views of such a man may be on his first entering a neighbourhood,
./english.txt:this truth is so well fixed in the minds of the surrounding families,
./english.txt:The surrounding was quite overwhelming.
Notice that when searching in a directory, the console output includes the file path for each matching line, distinguishing it from searches within a single file.
When searching in directories, you can include or exclude specific files using the --include
and --exclude
flags.
For example, you can exclude the English text file from the previous search:
grep --exclude 'english.txt' 'su' ./*
The terminal will then display:
./code:const sum = number1 + number2;
./code:console.log('The sum of ' + number1 + ' and ' + number2 + ' is ' + sum);
You could achieve the same result by including only the code file in the search:
grep --include 'code' 'su' ./*
It’s important to understand that the file names used in --include
and --exclude
are also treated as regular expressions.
For instance, you can do the following:
grep --include '*s*1' ' ' ./*
This command searches for a space character only in files that contain the letter "s" and end with the digit "1" in their names.
In addition to excluding files, you can exclude entire directories from your search.
First, let’s move up one level:
cd
Now perform a recursive search in the current directory while excluding specific folders using the --exclude-dir
option:
grep --exclude-dir='files' -R 'su' ./*
In this case, the folder named files will be excluded from the search results.
Let’s navigate back to the folder with the files:
cd files
In most UNIX-like systems, the grep
command provides powerful capabilities for searching text within the file system.
Additionally, grep
is well-suited for use within Linux pipelines, enabling it to process external files and the output of other console commands. This flexibility is achieved through using regular expressions and various configurable search flags.
By combining all the features of this utility, you can tackle a wide range of search tasks. In many ways, grep
is like a "Swiss Army knife" for finding information in Linux-based operating systems.