Skip to main content

grep

grep (Global Regular Expression Print) searches files or stdin for lines matching a pattern and prints matching lines. It is the standard tool for filtering log files, searching code, and extracting information from command output in Linux environments.

Understanding grep

What Is grep in Simple Terms

grep reads input line by line and prints only the lines that match a pattern. The pattern can be a simple string or a regular expression. It is the first tool to reach for when you need to find something in a log file, config file, or command output.

grep 'ERROR' /var/log/app.log — prints every line containing ERROR. Simple, fast, and handles files of any size.

◈ DIAGRAM
+------------------------------------------+
| Input: /var/log/app.log (1000 lines) |
+------------------------------------------+
|
v
+------------------------------------------+
| grep -E 'ERROR|FATAL' -n -A 2 |
| Reads line by line |
| Evaluates regex against each line |
+------------------------------------------+
|
match found
|
v
+------------------------------------------+
| Output: matching lines + line numbers |
| 42:2024-01-15 ERROR Connection failed |
| 43: at payment.js:123 |
+------------------------------------------+

Practical Commands

Bash
## Basic pattern search
grep 'ERROR' /var/log/app.log
## Case-insensitive search
grep -i 'error' /var/log/app.log
## Invert match (lines NOT containing pattern)
grep -v 'DEBUG' /var/log/app.log
## Show line numbers
grep -n 'ERROR' /var/log/app.log
## Count matching lines
grep -c 'ERROR' /var/log/app.log
## Show filenames only (useful with multiple files)
grep -l 'ERROR' /var/log/*.log
## Recursive search through directories
grep -r 'database_url' /etc/
grep -r 'API_KEY' /opt/apps/ --include='*.py'
## Show context: 3 lines before and after match
grep -B 3 -A 3 'CRITICAL' /var/log/app.log
## Extended regex (alternation, +, ?)
grep -E 'ERROR|FATAL|CRITICAL' /var/log/app.log
grep -E 'error[0-9]+' /var/log/app.log
## Perl regex (lookahead, lookbehind)
grep -P '(?<=user_id=)\d+' /var/log/app.log
## Quiet mode (exit code only, no output)
if grep -q 'FATAL' /var/log/app.log; then
echo "Fatal errors found!"
fi
## Search compressed files
zgrep 'ERROR' /var/log/app.log.gz
## Common production log analysis patterns:
## Count errors by hour
grep 'ERROR' /var/log/app.log | awk '{print $1, $2}' | cut -c1-13 | sort | uniq -c
## Find IPs with most failed logins
grep 'Failed password' /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -10
## Extract all unique error messages
grep 'ERROR' /var/log/app.log | sed 's/.*ERROR: //' | sort | uniq -c | sort -rn

Troubleshooting

Symptom Command What to Check
Pattern not matching `echo 'test' grep 'pattern'`
Too many results Add -v or more specific pattern Filter out unwanted lines
Binary file skipped grep -a or `strings file grep`
Tip

grep -E (extended regex) is almost always better than basic grep for production log analysis. It supports | for alternation, + for one-or-more, and ? for optional — without needing to escape them. Use grep -E 'ERROR|WARN|FATAL' instead of grep 'ERROR\|WARN\|FATAL'.

Remember

grep exit code 0 means matches found, exit code 1 means no matches, exit code 2 means an error occurred. This makes grep -q pattern file perfect for conditionals in scripts — it exits immediately on first match without printing anything.

Frequently Asked Questions

What's the difference between grep, egrep, and grep -P that actually affects how you write patterns?

Plain grep uses Basic Regular Expressions (BRE), where metacharacters like `+`, `?`, and `|` must be escaped (`\+`) to have special meaning. `egrep` (or `grep -E`) uses Extended Regular Expressions (ERE), where those characters work unescaped. `grep -P` enables PCRE (Perl-compatible regex), adding lookaheads/lookbehinds and non-greedy quantifiers that neither BRE nor ERE support — necessary for patterns like matching text NOT followed by a certain string.

What's a common grep mistake when searching logs at scale?

Using grep without `-F` on a pattern that's actually a literal string containing regex special characters (like an IP address with dots, or a URL) — the dots match any character, not just literal periods, occasionally producing false-positive matches on large log files. For pure literal-string search, `grep -F` (fixed-string mode) is both more correct and noticeably faster than treating a literal as a regex, since it skips the regex engine entirely.