Grep Command in Linux with Examples

By 

Updated on

18 min read

Grep Command in Linux

Grep is one of the most commonly used commands in Linux. The name stands for “Global Regular Expression Print”.

The grep command searches for a text pattern in one or more files and prints every line that matches. It is a powerful tool for searching and analyzing large amounts of text data quickly and efficiently. You can use it to search for specific words, phrases, or regular expressions in files of any size, from small configuration files to large log files. If no files are specified, grep reads from standard input, which is usually the output of another command.

This guide covers the most common GNU grep options with practical examples.

To pick the files before you search them, our find command builder puts together the find command and its -exec or xargs handoff to grep.

grep Command Syntax

The syntax for the grep command is as follows:

txt
grep [OPTIONS] PATTERN [FILE...]

The items in square brackets are optional.

  • OPTIONS - Zero or more options. Grep includes a number of options that control its behavior.
  • PATTERN - The search pattern (string or regular expression).
  • FILE - Zero or more input file names.

To search a file, the user running the command must have read access to it.

Search for a String in Files

The most basic usage of the grep command is to search for a string (text) in a file.

For instance, to find all lines containing the string “bash” in the /etc/passwd file, run the following command:

Terminal
grep bash /etc/passwd

The output shows every line that contains the matching string:

output
root:x:0:0:root:/root:/bin/bash
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bash

If the string contains spaces, enclose it in single or double quotation marks:

Terminal
grep "Gnome Display Manager" /etc/passwd

By default, grep is case-sensitive, meaning uppercase and lowercase characters are treated as distinct.

To ignore case when searching, use the -i option (or --ignore-case).

For example, searching for “Zebra” without -i will not match lowercase entries:

Terminal
grep Zebra /usr/share/dict/words

No output is produced because there are no lines matching the exact case. If you perform a case-insensitive search using the -i option, it will match all variations:

Terminal
grep -i Zebra /usr/share/dict/words
output
zebra
zebra's
zebras

Search for Full Words

When searching for a string, grep displays all lines where the string appears, even if it is embedded in a larger word.

For example, if you search for “gnu”, grep will match lines containing “gnu” as well as words like “cygnus” or “magnum”:

Terminal
grep gnu /usr/share/dict/words
output
cygnus
gnu
interregnum
lignum
magnum
magnuson
sphagnum
wingnut

To return only lines where the specified string is a whole word (enclosed by non-word characters), use the -w option (or --word-regexp):

Terminal
grep -w gnu /usr/share/dict/words
output
gnu
Info
Word characters include alphanumeric characters (a-z, A-Z, and 0-9) and underscores (_). All other characters are considered non-word characters.

Match Whole Lines

The -w option still matches a word anywhere in the line. To match the entire line, use the -x option (or --line-regexp).

This is the reliable way to test for an exact configuration value. A commented line such as #PermitRootLogin yes will not match:

Terminal
grep -x "PermitRootLogin yes" /etc/ssh/sshd_config

For a regular expression, -x behaves as if you had wrapped the pattern in parentheses and surrounded it with ^ and $.

Invert Match (Exclude)

Use the -v option (or --invert-match) to display lines that do not match a pattern.

For example, to print lines that do not contain the string “nologin”:

Terminal
grep -v nologin /etc/passwd
output
root:x:0:0:root:/root:/bin/bash
colord:x:124:124::/var/lib/colord:/bin/false
git:x:994:994:git daemon user:/:/usr/bin/git-shell
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bash

To recursively search for a pattern, invoke grep with the -r option (or --recursive). When this option is used, grep searches through all files in the specified directory and its subdirectories, skipping symlinks that are encountered recursively.

To follow all symbolic links , use the -R option (or --dereference-recursive) instead.

Here is an example showing how to search for the string linuxize.com in all files inside the /etc directory:

Terminal
grep -r linuxize.com /etc

The output includes matching lines prefixed by the full path to the file:

output
/etc/hosts:127.0.0.1 node2.linuxize.com
/etc/nginx/sites-available/linuxize.com:    server_name linuxize.com   www.linuxize.com;

If you use the -R option, grep will follow all symbolic links:

Terminal
grep -R linuxize.com /etc

Notice the last line in the output below. It is not printed when grep is invoked with -r because files inside Nginx’s sites-enabled directory are symlinks to configuration files inside sites-available:

output
/etc/hosts:127.0.0.1 node2.linuxize.com
/etc/nginx/sites-available/linuxize.com:    server_name linuxize.com   www.linuxize.com;
/etc/nginx/sites-enabled/linuxize.com:    server_name linuxize.com   www.linuxize.com;

For faster recursive searches in code repositories, ripgrep is often a better default because it respects ignore files and searches recursively without extra flags.

Show Only the Filename

To suppress the default grep output and print only the names of files containing a match, use the -l option (or --files-with-matches).

The following command searches for all files ending with .conf in the current working directory and displays only the file names:

Terminal
grep -l linuxize.com *.conf
output
tmux.conf
haproxy.conf

The -l option is commonly used together with the recursive option -R:

Terminal
grep -Rl linuxize.com /tmp

The opposite option is -L (or --files-without-match). It prints the name of every input file that produced no match. Use it for audits, such as finding configuration files that are missing a required directive:

Terminal
grep -L "PermitRootLogin" /etc/ssh/sshd_config.d/*.conf

Show Line Numbers

The -n option (or --line-number) tells grep to prefix each matching line with its line number in the file.

For instance, to display matching lines from /etc/services containing the string 10000 with their line numbers:

Terminal
grep -n 10000 /etc/services

The output shows that the matches are found on lines 10423 and 10424:

output
10423:ndmp            10000/tcp
10424:ndmp            10000/udp

Count Matches

To print only the number of matching lines instead of the lines themselves, use the -c option (or --count).

In the following example, we count the number of accounts that have /usr/bin/zsh as their shell:

Terminal
grep -c '/usr/bin/zsh' /etc/passwd
output
4

The -o option (or --only-matching) tells grep to print only the matched portion of each line, rather than the entire line. This is especially useful when extracting specific patterns with regular expressions.

For example, to extract all words starting with “log” from a file:

Terminal
grep -o 'log[a-z]*' /var/log/syslog | head -5

Highlight Matches with Color

The --color option surrounds each match with terminal escape sequences, so the matching text stands out from the rest of the line. Use the value auto in most cases. It enables color when the output goes to a terminal and disables it when the output is piped or redirected:

Terminal
grep --color=auto "error" /var/log/syslog

Most distributions already alias grep to grep --color=auto. That is why matches appear highlighted without the option. To keep color through a pipe, use --color=always. The escape sequences then become part of the text that the next command reads.

Context Lines

By default, grep prints only the lines that match. You can use context options to also display lines surrounding each match.

To print a specific number of lines before each match, use the -B option (or --before-context):

Terminal
grep -B 3 "error" /var/log/syslog

To print a specific number of lines after each match, use the -A option (or --after-context):

Terminal
grep -A 3 "error" /var/log/syslog

To print lines both before and after each match, use the -C option (or --context):

Terminal
grep -C 3 "error" /var/log/syslog

When multiple matches are close together, grep separates groups of context lines with --.

Using Grep to Filter Command Output

A command’s output can be filtered with grep through piping, and only lines matching a given pattern will be printed. This is one of the most common uses of grep.

For instance, to find which processes are running as user www-data, you can pipe the output of the ps command to grep:

Terminal
ps -ef | grep www-data
output
www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

Note that grep may also match its own process in the output. A common trick to avoid this is to use a character class in the pattern:

Terminal
ps -ef | grep '[w]ww-data'

By wrapping the first character in brackets, the grep command itself no longer matches the pattern.

Filtering a Live Stream

Filtering a continuous stream, such as a log file followed with tail -f, works the same way:

Terminal
tail -f /var/log/nginx/error.log | grep "upstream"

Matching lines may appear in bursts rather than immediately. When grep writes to a pipe, it buffers output in large blocks instead of line by line. Add the --line-buffered option to flush every matching line as soon as it is found:

Terminal
tail -f /var/log/nginx/error.log | grep --line-buffered "upstream"

This costs a little performance on large searches. Use it for live monitoring, not for one-off searches through big files.

Search for Multiple Strings (Patterns)

Two or more search patterns can be joined using the OR operator |.

By default, grep interprets the pattern as a basic regular expression, where | must be escaped with a backslash:

Terminal
grep 'fatal\|error\|critical' /var/log/nginx/error.log

If you use the extended regular expression option -E, the operator does not need to be escaped:

Terminal
grep -E 'fatal|error|critical' /var/log/nginx/error.log

For more complex multi-pattern searches, see Grep Multiple Patterns .

Basic Regular Expressions

GNU Grep has three regular expression feature sets: Basic, Extended, and Perl-compatible.

By default, grep interprets the pattern as a basic regular expression (BRE), where all characters except the meta-characters match themselves.

Below is a list of the most commonly used meta-characters:

  • ^ - Matches the start of a line. In the following example, kangaroo matches only if it occurs at the beginning of a line:

    Terminal
    grep "^kangaroo" file.txt
  • $ - Matches the end of a line. Here, kangaroo matches only if it occurs at the end of a line:

    Terminal
    grep "kangaroo$" file.txt
  • . - Matches any single character. To match anything that begins with kan, then has two characters, and ends with roo:

    Terminal
    grep "kan..roo" file.txt
  • [ ] - Matches any single character enclosed in the brackets. For instance, to find lines that contain accept or accent:

    Terminal
    grep "acce[np]t" file.txt
  • [^ ] - Matches any single character not enclosed in the brackets. The following pattern matches strings like coca or coma, but not cola:

    Terminal
    grep "co[^l]a" file.txt

To escape the special meaning of a meta-character, use the \ (backslash) symbol.

Extended Regular Expressions

To interpret the pattern as an extended regular expression (ERE), use the -E option (or --extended-regexp). Extended regular expressions include all basic meta-characters plus additional ones such as +, ?, |, and ().

Here is an example that matches and extracts all email addresses from a file:

Terminal
grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" file.txt

The following example matches and extracts all valid IPv4 addresses from a file:

Terminal
grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt

The -o option prints only the matched portion of each line, not the entire line.

Perl-Compatible Regular Expressions

The third feature set is enabled with the -P option (or --perl-regexp). It interprets the pattern as a Perl-compatible regular expression and adds constructs such as \d, \t, lookarounds, and non-greedy quantifiers. GNU basic and extended regular expressions already recognize \w, \W, \s, and \S as special backslash expressions.

For example, to find lines where a number is preceded by a dollar sign, without printing the dollar sign itself:

Terminal
grep -Po '(?<=\$)\d+' invoice.txt

The -P option is a GNU extension. It is missing from some builds, including the BSD grep shipped with macOS. For the full syntax of all three feature sets, see the guide to regular expressions in grep .

Search Only Specific File Types

The --include option is the counterpart of --exclude. Instead of listing what to skip, you state which file names to search. Combined with -r, it is the shortest way to search one file type across a project.

To search only Python files for the string “requests”:

Terminal
grep -r --include="*.py" "requests" .

Quote the pattern. Otherwise the shell expands it against the current directory before grep ever runs. Repeat the option to cover several types:

Terminal
grep -r --include="*.py" --include="*.cfg" "requests" .

Excluding Files and Directories

When searching recursively, you can exclude specific files or directories using --exclude and --exclude-dir.

To exclude all .log files from a recursive search:

Terminal
grep -r --exclude="*.log" "pattern" /path/to/directory

To exclude multiple file types, repeat the --exclude option:

Terminal
grep -r --exclude="*.log" --exclude="*.tmp" "pattern" /path/to/directory

To exclude a directory from the search:

Terminal
grep -r --exclude-dir="node_modules" "pattern" /path/to/directory

For more details and examples, see Grep Exclude .

Quiet Mode

The -q option (or --quiet) tells grep to run silently without displaying anything on standard output. If a match is found, the command exits with status 0. This is useful in shell scripts where you want to check whether a file contains a string and perform an action based on the result.

Here is an example of using grep in quiet mode as a test command in an if statement :

sh
if grep -q PATTERN filename
then
    echo pattern found
else
    echo pattern not found
fi

Using Shell Variables with Grep

When using grep in shell scripts, you can pass shell variables as the search pattern. Enclose the variable in double quotes to prevent word splitting and globbing:

Terminal
pattern="search term"
grep "$pattern" file.txt

To use a variable as a fixed string (disabling regex interpretation), combine it with the -F option:

Terminal
grep -F "$pattern" file.txt

Limit the Number of Matches

The -m option (or --max-count) tells grep to stop reading a file after a specified number of matching lines. This is useful when working with large files and you only need the first few matches.

For example, to print only the first five lines containing “error” in a log file:

Terminal
grep -m 5 "error" /var/log/syslog

Grep stops reading the file as soon as it finds five matches, which can save a lot of time on large files.

Suppress Error Messages

By default, grep prints error messages when it cannot read a file or when a file does not exist. The -s option (or --no-messages) silences these messages.

This is helpful in shell scripts where you want to ignore “No such file or directory” or “Permission denied” warnings:

Terminal
grep -s "pattern" /etc/*.conf

Any files that cannot be read are skipped silently, and only the actual matches are printed.

Hide Filenames in Output

When grep searches multiple files, it prefixes each matching line with the file name. The -h option (or --no-filename) suppresses these prefixes and prints only the matching lines.

For example, to search for “PermitRootLogin” across all SSH configuration files without showing file names:

Terminal
grep -h "PermitRootLogin" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf

This is useful when piping the output to another command or when the file names would only add noise to the result.

Search Binary Files as Text

Grep treats binary files differently from text files and prints a message like Binary file FILE matches instead of the actual content. The -a option (or --text) forces grep to process binary files as if they were text.

To search for a string in a binary file or a data file that contains non-text bytes:

Terminal
grep -a "version" archive.dat

The matching lines are printed even though the file may contain non-printable characters. Be aware that the output may include control characters that affect your terminal.

Search Compressed Files

Rotated log files are usually compressed. A plain grep over /var/log/syslog* silently misses everything in the .gz archives. The zgrep wrapper decompresses each file on the fly and passes the result to grep. It accepts the same options:

Terminal
zgrep -c "error" /var/log/syslog.2.gz

It also handles a mix of compressed and plain files in one command. That is what you need when a search spans a whole rotation cycle:

Terminal
zgrep -i "out of memory" /var/log/syslog*

Companion wrappers exist for other formats, including bzgrep for bzip2 and xzgrep for xz archives.

Combining Grep with find

When you need more control over which files are searched, combine grep with the find command using -exec. This is helpful when you want to filter by file attributes such as modification time, size, or permissions before searching their contents.

For example, to search for “TODO” in all .py files modified in the last seven days:

Terminal
find . -type f -name "*.py" -mtime -7 -exec grep -l "TODO" {} +

The find command locates the matching files, and grep -l prints the names of files that contain the pattern. Using + instead of \; passes files to grep in batches, which is much faster than invoking grep once for each file.

Troubleshooting

\d matches nothing or behaves unexpectedly
The \d shorthand belongs to Perl-compatible regular expressions. In basic and extended patterns, a backslash before an unrecognized ordinary character has unspecified behavior. Do not rely on grep -E '\d+' matching digits or the letter d. Use a bracket expression that works everywhere, grep -E '[0-9]+' or grep -E '[[:digit:]]+', or switch the engine with grep -P '\d+'.

A tab in the pattern does not match
The \t escape is also PCRE syntax. Outside PCRE, its interpretation is unspecified, so do not rely on grep '\t' matching a tab or the letter t. Use grep -P '\t', or let the shell insert a real tab with grep $'\t' file.txt.

grep prints “Binary file FILE matches”
Grep classified the file as binary, often because it found null bytes or encountered encoding errors. It suppresses the matching content to avoid sending binary data to your terminal. Pass -a to treat the file as text, or -I to skip binary files entirely during a recursive search. Log files often trigger this after a partial write. Check the file before assuming the message is wrong.

A pattern that starts with a dash is read as an option
Grep parses grep -v- file.txt as options. Mark the pattern explicitly with -e, as in grep -e "-v-" file.txt, or end option parsing with --, as in grep -- "-v-" file.txt.

The search matches unexpected files or nothing at all
The shell expands an unquoted pattern before grep runs. A command such as grep *.conf /etc/hosts can turn into something completely different. Quote every pattern that contains *, ?, [, $, or spaces.

Recursive searches fill the screen with “Permission denied”
Those messages come from directories your user cannot read. Add the -s option to silence them, or run the search through sudo when you genuinely need the protected paths.

Patterns anchored with $ fail on files from Windows
Files with CRLF line endings keep a carriage return at the end of every line. The line really ends with value\r, so grep "value$" never matches. Confirm the line endings with file data.txt. Then convert the file with dos2unix, or allow for the extra character with grep -P "value\r?$".

Quick Reference

For a printable quick reference, see the Grep cheatsheet .

TaskCommand
Search for a stringgrep "pattern" file
Case insensitive searchgrep -i "pattern" file
Whole word matchgrep -w "word" file
Whole line matchgrep -x "whole line" file
Invert matchgrep -v "pattern" file
Recursive searchgrep -r "pattern" /path
Show filenames onlygrep -rl "pattern" /path
Show files without a matchgrep -L "pattern" file1 file2
Show line numbersgrep -n "pattern" file
Count matchesgrep -c "pattern" file
Print only matching partgrep -o "pattern" file
Lines before matchgrep -B 3 "pattern" file
Lines after matchgrep -A 3 "pattern" file
Lines around matchgrep -C 3 "pattern" file
Multiple patternsgrep -e "pat1" -e "pat2" file
Fixed string (no regex)grep -F "literal.string" file
Perl-compatible regexgrep -P '\d+' file
Search one file typegrep -r --include="*.py" "pattern" /path
Exclude filesgrep -r --exclude="*.log" "pattern" /path
Exclude directoriesgrep -r --exclude-dir=".git" "pattern" /path
Recursive with line numbersgrep -rn "pattern" /path
Hide filenamesgrep -h "pattern" file1 file2
Highlight matchesgrep --color=auto "pattern" file
Limit matchesgrep -m 5 "pattern" file
Suppress errorsgrep -s "pattern" file
Search binary as textgrep -a "pattern" binary
Search compressed logszgrep "pattern" /var/log/syslog*
Filter a live streamtail -f file | grep --line-buffered "pattern"
Find and grepfind . -name "*.py" -exec grep -l "pattern" {} +

FAQ

What does grep do?
The grep command searches text for lines that match a pattern. It reads input from files or standard input, applies a search pattern (either a literal string or a regular expression), and prints every matching line. It is one of the most-used tools for filtering log files, extracting data from command output, and finding code in projects.

What does grep mean?
The name stands for “Global Regular Expression Print”. It comes from the ed text editor command g/re/p, which globally searches for a regular expression and prints matching lines. Grep became a standalone Unix utility in 1973 and has shipped with every major Unix-like system since.

What is the difference between grep, egrep, and fgrep?
They select different pattern engines. The egrep command is equivalent to grep -E. It reads the pattern as an extended regular expression, so meta-characters like +, ?, |, and () do not need to be escaped. The fgrep command is equivalent to grep -F. It treats the pattern as a fixed string, so a character such as . matches only a literal dot. Both are deprecated and print a warning on current GNU grep releases. Use grep -E and grep -F instead.

How do I search for a string in all files in a directory?
Use the -r (recursive) option: grep -r "pattern" /path/to/directory. This searches all files in the directory and its subdirectories. Add --include="*.txt" to limit the search to specific file types.

How do I search for multiple words with grep?
Use the -E option with the alternation operator: grep -E "word1|word2|word3" file. Without -E, escape the pipe characters: grep "word1\|word2\|word3" file.

What is the difference between grep, sed, and awk?
Grep is designed for searching and filtering lines that match a pattern. Sed is a stream editor for transforming text with find-and-replace operations. Awk is a full programming language for field-based text processing and data extraction. Use grep to find lines, sed to modify text, and awk to process columnar data.

Conclusion

The grep command is an essential tool for searching text patterns in files and command output. Combined with regular expressions and options like -r, -i, and -E, it handles everything from simple string searches to complex pattern matching.

For more information, see the official Grep manual .

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page