The grep command searches text for a pattern and prints the matching lines. Most Linux users know grep "hello" file. Fewer users know the options that make grep fast to use: recursive search, context lines, multiple patterns, and regular expressions. This tutorial shows each option with a short example and its real output.
grep options at a glance
| Option | What it does | Example |
|---|---|---|
-i | ignore upper and lower case | grep -i 'hello' file.txt |
-v | show only lines without a match | grep -v 'hello' file.txt |
-w | match whole words only | grep -w 'hello' file.txt |
-r | search sub-directories | grep -r 'hello' . |
-E | extended regex with +, ? and () | grep -E 'hell?o' file.txt |
-e | give more than one pattern | grep -e 'helo' -e 'Hello' file.txt |
-c | count the matching lines | grep -c 'hel' file.txt |
-n | show the line number | grep -n 'hello' file.txt |
-o | print only the matching text | grep -o 'hel[a-z]*' file.txt |
-l / -L | list files with / without a match | grep -l 'hel' *.txt |
-A / -B / -C | show lines after / before / around a match | grep -C 2 'ERROR' log.txt |
-f | read the patterns from a file | grep -f patterns.txt file.txt |
What is grep?
The name grep comes from the old ed command g/re/p: global regular expression print. grep reads files or the output of another command. It prints each line that contains the pattern. The pattern can be a plain word or a regular expression.
You use grep for log files, source code, and the output of other commands. For example, this command prints each line of xyz.txt that contains the word “hello”:
grep "hello" xyz.txt
If you do not know regular expressions yet, try the interactive lessons on regexone.com. You can use grep without regular expressions too.
grep syntax
grep [options] pattern [file...]
Parts in square brackets are optional. If you give no file, grep reads from standard input. This is how you use grep after a pipe:
lspci | grep VGA
egrep or grep -E?
egrep is the same as grep -E. Both let you use +, ?, | and () in the pattern without a backslash. On Ubuntu, egrep is only a small script that calls grep -E. GNU grep has warned about egrep since version 3.8, because it is obsolete. Debian and Ubuntu do not show this warning. Use grep -E in new scripts anyway.
The sample files
All examples use this file file.txt:
hello world
Hello world
helo typo
hellothere
Create it with this command:
printf 'hello world\nHello world\nhelo typo\nhellothere\n' > file.txt
Note: In Bash, echo "a\nb" does not create a new line. Use printf instead.
grep options
You can write most options in a short form and in a long form:
- The short form has one minus sign and one letter, for example
-c. You can join short options:-ciw. - The long form has two minus signs and a word, for example
--count.
Extended regex: -E
With -E you can use +, ?, | and () in the pattern.
grep -E 'hell?o' file.txt
This pattern matches “hello” and “helo”:
hello world
helo typo
hellothere
Search sub-directories: -r
Add -r to search all files in a directory and below. The path after the pattern is the start folder. A dot means the current folder. In this example, the folder sub holds the file a.php with the line “hello from sub”.
grep -r 'hello' .
Output:
./file.txt:hello world
./file.txt:hellothere
./sub/a.php:hello from sub
In a recursive search, grep puts the file name in front of each match. Use --include to search only some files. Add -n to see the line numbers:
grep -rn --include='*.php' 'hello' .
Output:
./sub/a.php:1:hello from sub
The option -R also follows all symbolic links. The option -r follows only the links that you give on the command line.
Show the lines that do not match: -v
Use -v to invert the match.
grep -v 'hello' file.txt
Output:
Hello world
helo typo
Ignore case: -i
By default grep is case-sensitive. Add -i to ignore upper and lower case.
grep -i 'hello' file.txt
Output:
hello world
Hello world
hellothere
Match whole words: -w
By default grep finds the pattern inside longer words too. Add -w to find whole words only.
grep -w 'hello' file.txt
Output:
hello world
The line “hellothere” does not match, because “hello” is only a part of the word.
Search for several patterns
There are two ways to find lines with one pattern OR another pattern.
Give each pattern with -e:
grep -e 'helo' -e 'Hello' file.txt
Or separate the patterns with a vertical bar and use -E:
grep -E 'helo|there' file.txt
The first command prints “Hello world” and “helo typo”. The second command prints “helo typo” and “hellothere”.
To find lines that contain ALL patterns, use a pipe. The second grep searches the output of the first grep:
grep 'hel' file.txt | grep 'there'
Change the output of grep
Count the matches: -c
Use -c or --count to print only the number of matching lines.
grep -c 'hel' file.txt
Output:
3
Show the line numbers: -n
Use -n to put the line number in front of each match. This is useful for source code.
grep -n 'hello' file.txt
Output:
1:hello world
4:hellothere
Show lines before and after a match: -A, -B, -C
In a log file, the matching line is often not enough. You need the lines around it. Three options do this:
-A <number>(after) shows lines AFTER the match-B <number>(before) shows lines BEFORE the match-C <number>(context) shows lines before AND after the match
The next examples use this file log.txt:
printf 'line one\nline two\nERROR: disk full\nline four\nline five\nline six\n' > log.txt
grep -A 1 'ERROR' log.txt
Output:
ERROR: disk full
line four
With -B 1, grep prints “line two” and “ERROR: disk full”. With -C 1, grep prints “line two”, “ERROR: disk full” and “line four”. If the context blocks of two matches do not touch, grep separates them with a line that holds --.
Print only the match: -o
Normally grep prints the whole line. With -o (only matching) grep prints only the part that matches the pattern. Each match gets its own line.
grep -o 'hel[a-z]*' file.txt
Output:
hello
helo
hellothere
Use -o with a regular expression when you need only the e-mail addresses or IP addresses from a file, not the rest of the line.
Print only the file names: -l
Use -l (a lowercase L) to print the names of the files that contain a match. grep does not print the lines.
grep -l 'hel' *.txt
Output:
file.txt
Print the files without a match: -L
Use -L to print the names of the files that do NOT contain the pattern.
grep -L 'hello' *.txt
Output:
log.txt
Color the matches
grep can color the matched text in each line. Add this alias to your ~/.bashrc or ~/.zshrc:
alias grep='grep --color=auto'
On many systems, for example Ubuntu, this alias is already set.
Note: Old tutorials use export GREP_OPTIONS='--color=auto'. This does not work any more. GNU grep ignores the variable GREP_OPTIONS since version 3.6.
To change the color, set GREP_COLORS:
export GREP_COLORS='mt=1;32'
The old variable GREP_COLOR is obsolete since grep 3.8 and prints a warning. Replace the numbers in the quotes with one of these color codes:
Black 0;30 Dark Gray 1;30
Blue 0;34 Light Blue 1;34
Green 0;32 Light Green 1;32
Cyan 0;36 Light Cyan 1;36
Red 0;31 Light Red 1;31
Purple 0;35 Light Purple 1;35
Brown 0;33 Yellow 1;33
Light Gray 0;37 White 1;37
Read the patterns from a file: -f
If you use a long pattern often, save it in a file. Then load it with -f <file>. The file holds one pattern in each line.
printf 'helo\nHello\n' > patterns.txt
grep -f patterns.txt file.txt
Output:
Hello world
helo typo
This also works with regular expressions. Save each regex that you use often under a clear name in one folder. Over time you get a library of regexes that you can use again.
Practical examples
Show the graphics card
lspci | grep VGA
Find lines that start with “foobar” in two files
grep '^foobar' file1.txt file2.txt
Find empty lines
grep -n '^$' file.php
Show all hard disks
dmesg | grep -E '(s|h)d[a-z]'
List all mysql processes
ps aux | grep '[m]ysql'
The brackets around the first letter have a purpose. Without them, the output also contains the grep command itself, because its command line contains the word “mysql”. The pattern [m]ysql does not match its own command line.
Find all TODO comments in your code
grep -rn 'TODO' --include='*.php' .
Summary
grep has many options, and regular expressions make it a strong tool. Start with -r, -i, -n and -v. Add -A, -B and -C when you read log files, and -o when you want only the matching text.
Something is unclear or missing? Please leave a comment below, and I will improve the article.