Deutsche Version →

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

OptionWhat it doesExample
-iignore upper and lower casegrep -i 'hello' file.txt
-vshow only lines without a matchgrep -v 'hello' file.txt
-wmatch whole words onlygrep -w 'hello' file.txt
-rsearch sub-directoriesgrep -r 'hello' .
-Eextended regex with +, ? and ()grep -E 'hell?o' file.txt
-egive more than one patterngrep -e 'helo' -e 'Hello' file.txt
-ccount the matching linesgrep -c 'hel' file.txt
-nshow the line numbergrep -n 'hello' file.txt
-oprint only the matching textgrep -o 'hel[a-z]*' file.txt
-l / -Llist files with / without a matchgrep -l 'hel' *.txt
-A / -B / -Cshow lines after / before / around a matchgrep -C 2 'ERROR' log.txt
-fread the patterns from a filegrep -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:

  1. The short form has one minus sign and one letter, for example -c. You can join short options: -ciw.
  2. 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 --.

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.

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

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.