Grep Command in Linux with Examples

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:
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:
grep bash /etc/passwdThe output shows every line that contains the matching string:
root:x:0:0:root:/root:/bin/bash
linuxize:x:1000:1000:linuxize:/home/linuxize:/bin/bashIf the string contains spaces, enclose it in single or double quotation marks:
grep "Gnome Display Manager" /etc/passwdCase Insensitive Search
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:
grep Zebra /usr/share/dict/wordsNo 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:
grep -i Zebra /usr/share/dict/wordszebra
zebra's
zebrasSearch 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”:
grep gnu /usr/share/dict/wordscygnus
gnu
interregnum
lignum
magnum
magnuson
sphagnum
wingnutTo return only lines where the specified string is a whole word (enclosed by non-word characters), use the -w option (or --word-regexp):
grep -w gnu /usr/share/dict/wordsgnua-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:
grep -x "PermitRootLogin yes" /etc/ssh/sshd_configFor 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”:
grep -v nologin /etc/passwdroot: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/bashRecursive Search
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:
grep -r linuxize.com /etcThe output includes matching lines prefixed by the full path to the file:
/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:
grep -R linuxize.com /etcNotice 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:
/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:
grep -l linuxize.com *.conftmux.conf
haproxy.confThe -l option is commonly used together with the recursive option -R:
grep -Rl linuxize.com /tmpThe 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:
grep -L "PermitRootLogin" /etc/ssh/sshd_config.d/*.confShow 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:
grep -n 10000 /etc/servicesThe output shows that the matches are found on lines 10423 and 10424:
10423:ndmp 10000/tcp
10424:ndmp 10000/udpCount 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:
grep -c '/usr/bin/zsh' /etc/passwd4Print Only the Matching Part
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:
grep -o 'log[a-z]*' /var/log/syslog | head -5Highlight 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:
grep --color=auto "error" /var/log/syslogMost 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):
grep -B 3 "error" /var/log/syslogTo print a specific number of lines after each match, use the -A option (or --after-context):
grep -A 3 "error" /var/log/syslogTo print lines both before and after each match, use the -C option (or --context):
grep -C 3 "error" /var/log/syslogWhen 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:
ps -ef | grep www-datawww-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 processNote 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:
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:
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:
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:
grep 'fatal\|error\|critical' /var/log/nginx/error.logIf you use the extended regular expression option -E, the operator does not need to be escaped:
grep -E 'fatal|error|critical' /var/log/nginx/error.logFor 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,kangaroomatches only if it occurs at the beginning of a line:Terminalgrep "^kangaroo" file.txt$- Matches the end of a line. Here,kangaroomatches only if it occurs at the end of a line:Terminalgrep "kangaroo$" file.txt.- Matches any single character. To match anything that begins withkan, then has two characters, and ends withroo:Terminalgrep "kan..roo" file.txt[ ]- Matches any single character enclosed in the brackets. For instance, to find lines that containacceptoraccent:Terminalgrep "acce[np]t" file.txt[^ ]- Matches any single character not enclosed in the brackets. The following pattern matches strings likecocaorcoma, but notcola:Terminalgrep "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:
grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" file.txtThe following example matches and extracts all valid IPv4 addresses from a file:
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.txtThe -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:
grep -Po '(?<=\$)\d+' invoice.txtThe -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”:
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:
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:
grep -r --exclude="*.log" "pattern" /path/to/directoryTo exclude multiple file types, repeat the --exclude option:
grep -r --exclude="*.log" --exclude="*.tmp" "pattern" /path/to/directoryTo exclude a directory from the search:
grep -r --exclude-dir="node_modules" "pattern" /path/to/directoryFor 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
:
if grep -q PATTERN filename
then
echo pattern found
else
echo pattern not found
fiUsing 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:
pattern="search term"
grep "$pattern" file.txtTo use a variable as a fixed string (disabling regex interpretation), combine it with the -F option:
grep -F "$pattern" file.txtLimit 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:
grep -m 5 "error" /var/log/syslogGrep 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:
grep -s "pattern" /etc/*.confAny 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:
grep -h "PermitRootLogin" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.confThis 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:
grep -a "version" archive.datThe 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:
zgrep -c "error" /var/log/syslog.2.gzIt 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:
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:
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 .
| Task | Command |
|---|---|
| Search for a string | grep "pattern" file |
| Case insensitive search | grep -i "pattern" file |
| Whole word match | grep -w "word" file |
| Whole line match | grep -x "whole line" file |
| Invert match | grep -v "pattern" file |
| Recursive search | grep -r "pattern" /path |
| Show filenames only | grep -rl "pattern" /path |
| Show files without a match | grep -L "pattern" file1 file2 |
| Show line numbers | grep -n "pattern" file |
| Count matches | grep -c "pattern" file |
| Print only matching part | grep -o "pattern" file |
| Lines before match | grep -B 3 "pattern" file |
| Lines after match | grep -A 3 "pattern" file |
| Lines around match | grep -C 3 "pattern" file |
| Multiple patterns | grep -e "pat1" -e "pat2" file |
| Fixed string (no regex) | grep -F "literal.string" file |
| Perl-compatible regex | grep -P '\d+' file |
| Search one file type | grep -r --include="*.py" "pattern" /path |
| Exclude files | grep -r --exclude="*.log" "pattern" /path |
| Exclude directories | grep -r --exclude-dir=".git" "pattern" /path |
| Recursive with line numbers | grep -rn "pattern" /path |
| Hide filenames | grep -h "pattern" file1 file2 |
| Highlight matches | grep --color=auto "pattern" file |
| Limit matches | grep -m 5 "pattern" file |
| Suppress errors | grep -s "pattern" file |
| Search binary as text | grep -a "pattern" binary |
| Search compressed logs | zgrep "pattern" /var/log/syslog* |
| Filter a live stream | tail -f file | grep --line-buffered "pattern" |
| Find and grep | find . -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 .
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

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