grep β Pattern Search#
Syntax#
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] -e PATTERN -e PATTERN [FILE...]
grep [OPTIONS] -f PATTERNFILE [FILE...]
Essential flags#
| Flag | Meaning |
|---|
-i | Case-insensitive match |
-v | Invert match (non-matching lines) |
-n | Show line numbers |
-c | Print match count per file |
-l | Print only filenames with matches |
-L | Print only filenames with no match |
-r / -R | Recursive (follow symlinks with -R) |
-w | Match whole word only |
-x | Match whole line only |
-o | Print only the matching part of the line |
-q | Quiet β exit 0 if match found, no output |
-s | Suppress error messages about missing files |
-m N | Stop after N matches |
-h | Suppress filename prefix (multi-file mode) |
-H | Always print filename prefix |
Regex flavours#
| Flag | Engine | Notes |
|---|
grep | BRE (basic) | \+ | \( \) need backslash |
grep -E / egrep | ERE (extended) | + | () unescaped |
grep -P | PCRE | \d \w (?=...) lookaheads etc. |
grep -F / fgrep | Fixed string | No regex, fastest for literals |
Context lines#
grep -A 3 "ERROR" app.log # 3 lines After match
grep -B 2 "ERROR" app.log # 2 lines Before match
grep -C 5 "ERROR" app.log # 5 lines before and after (Context)
Character classes & anchors#
grep '^root' /etc/passwd # lines starting with "root"
grep 'bash$' /etc/passwd # lines ending with "bash"
grep '^$' file.txt # empty lines
grep -E '[0-9]{4}' data.txt # exactly 4 digits
grep -P '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' ips.txt # IPv4 addresses
Multiple patterns#
grep -e "error" -e "warn" -e "crit" /var/log/syslog
# Or from a file (one pattern per line)
grep -f patterns.txt logfile
Recursive search#
grep -r "TODO" ./src/
grep -rl "console.log" ./src/ # filenames only
grep -rn --include="*.py" "import" . # only .py files
grep -r --exclude="*.min.js" "fetch" . # skip minified files
grep -r --exclude-dir={.git,node_modules,dist} "pattern" .
Colour and output control#
grep --color=always "error" log | less -R # keep colour through pipe
grep -o '"[^"]*"' file.json # extract all quoted strings
grep -oP '(?<=href=")[^"]*' page.html # PCRE lookbehind β all href values
grep -n "" file.txt # number every line (cat -n alternative)
Count and statistics#
grep -c "ERROR" app.log # match count in one file
grep -rc "TODO" src/ | sort -t: -k2 -rn # per-file TODO counts, sorted
# Number of unique matching lines
grep "pattern" file | sort -u | wc -l
Exit codes#
| Code | Meaning |
|---|
0 | At least one match found |
1 | No match found |
2 | Error (bad option, missing file) |
# Use in conditionals
if grep -q "FAILED" build.log; then
echo "Build had failures"
fi
# Check without output
grep -qs "pattern" file && echo "found"
Binary files#
grep -a "pattern" binary.bin # treat binary as text
grep -I "pattern" * # skip binary files silently
grep --binary-files=text "str" img.bin
Practical pipelines#
# Find processes by name
ps aux | grep -v grep | grep nginx
# Extract unique IPs from access log
grep -oP '\d+\.\d+\.\d+\.\d+' access.log | sort -u
# Show lines between two patterns (inclusive)
grep -A 9999 "START" file | grep -B 9999 "END"
# Find files containing all of two patterns
grep -rl "alpha" . | xargs grep -l "beta"
# Lines that DON'T contain either of two words
grep -v -e "debug" -e "trace" app.log
# Highlight matches but show all lines
grep --color=always -E "error|$" app.log
Tips#
[!TIP]
Use grep -F for literal string searches (no regex overhead) β significantly faster on large files when you donβt need pattern matching.
[!TIP]
grep -P (PCRE) is not available on BSD/macOS by default. Use ggrep -P (via Homebrew grep) or switch to ripgrep which has PCRE2 built-in.