grep — Search Text with Regular Expressions
Search files and streams for text patterns with grep — BRE, ERE and PCRE regex, recursive search, context lines and precise output control.
grep is the go-to tool for finding text. It scans files or piped input line by line and prints every line that matches a pattern – from a plain literal string to a full regular expression. You reach for it many times a day: hunting through log files, searching a code base, filtering the output of another command, or checking a condition inside a script via its exit code. This guide covers the flags that matter most – case-insensitive and whole-word matching, recursive search, the three regex flavours (-E, -P, -F), context lines and output control.
Basic Search
grep '<pattern>' <file> — Search for a pattern in a file and print matching lines.
grep 'error' /var/log/sysloggrep '<pattern>' <file1> <file2> — Search for a pattern in multiple files.
grep 'TODO' app.js utils.jsgrep -r '<pattern>' <path> — Search recursively through all files in a directory.
grep -r 'console.log' src/grep -R '<pattern>' <path> — Search recursively and follow symbolic links.
grep -R 'import' /usr/local/lib/grep -i '<pattern>' <file> — Case-insensitive search.
grep -i 'warning' /var/log/sysloggrep -w '<pattern>' <file> — Match whole words only (not substrings).
grep -w 'error' app.loggrep -x '<pattern>' <file> — Match entire lines only.
grep -x 'OK' status.txtRegular Expressions
grep -E '<pattern>' <file> — Use extended regular expressions (ERE) — supports +, ?, |, () without escaping.
grep -E 'error|warning|fatal' app.loggrep -P '<pattern>' <file> — Use Perl-compatible regular expressions (PCRE) — supports lookahead, lookbehind, \d, etc.
grep -P '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' access.loggrep -F '<string>' <file> — Treat the pattern as a fixed string, not a regex (faster for literal matches).
grep -F '$(document).ready' app.jsgrep -E '^<pattern>' <file> — Match lines starting with a pattern.
grep -E '^#' config.inigrep -E '<pattern>$' <file> — Match lines ending with a pattern.
grep -E '\.js$' filelist.txtgrep -E '<a>|<b>' <file> — Match lines containing either pattern (alternation).
grep -E 'GET|POST' access.loggrep '\.<ext>' <file> — Escape special regex characters with backslash for literal match.
grep 'version 2\.0' changelog.txtOutput Control
grep -n '<pattern>' <file> — Show line numbers alongside matching lines.
grep -n 'function' app.jsgrep -c '<pattern>' <file> — Count the number of matching lines.
grep -c 'ERROR' app.loggrep -l '<pattern>' <files> — Print only the filenames that contain a match.
grep -rl 'TODO' src/grep -L '<pattern>' <files> — Print only the filenames that do not contain a match.
grep -rL 'use strict' src/*.jsgrep -o '<pattern>' <file> — Print only the matched part of each line, not the entire line.
grep -oE '[0-9]+\.[0-9]+\.[0-9]+' version.txtgrep -H '<pattern>' <file> — Always print the filename with each match.
grep -Hn 'error' *.loggrep -h '<pattern>' <files> — Suppress filenames in output when searching multiple files.
grep -h 'export' src/*.jsgrep --color=always '<pattern>' <file> — Highlight matches in color (useful when piping through less).
grep --color=always 'error' app.log | less -RContext Lines
grep -A <n> '<pattern>' <file> — Show n lines after each match.
grep -A 3 'Exception' error.loggrep -B <n> '<pattern>' <file> — Show n lines before each match.
grep -B 5 'FATAL' error.loggrep -C <n> '<pattern>' <file> — Show n lines before and after each match (context).
grep -C 2 'segfault' /var/log/kern.logInverting & Filtering
grep -v '<pattern>' <file> — Invert match — print lines that do not match the pattern.
grep -v '^#' config.inigrep -v -e '<a>' -e '<b>' <file> — Exclude lines matching any of several patterns.
grep -v -e '^#' -e '^$' config.inigrep -e '<a>' -e '<b>' <file> — Match lines containing any of multiple patterns.
grep -e 'error' -e 'warning' app.loggrep -f <patternfile> <file> — Read patterns from a file (one pattern per line).
grep -f keywords.txt document.txtRecursive Options
grep -r --include='<glob>' '<pattern>' <path> — Search recursively but only in files matching a glob pattern.
grep -r --include='*.php' 'require_once' /var/www/grep -r --exclude='<glob>' '<pattern>' <path> — Search recursively but skip files matching a glob pattern.
grep -r --exclude='*.min.js' 'function' src/grep -r --include='*.{js,ts}' '<pattern>' <path> — Search recursively in multiple file types using brace expansion.
grep -r --include='*.{js,ts}' 'import' src/grep -r --exclude-dir='<dir>' '<pattern>' <path> — Search recursively but skip specific directories.
grep -r --exclude-dir='node_modules' 'TODO' .grep -r --exclude-dir={<a>,<b>} '<pattern>' <path> — Skip multiple directories during recursive search.
grep -r --exclude-dir={node_modules,.git,dist} 'console' .Binary & Special Files
grep -a '<pattern>' <file> — Treat binary files as text.
grep -a 'version' program.bingrep -I '<pattern>' <file> — Skip binary files entirely (treat them as non-matching).
grep -rI 'config' /opt/grep -Z '<pattern>' <files> — Output null byte after each filename (for use with xargs -0).
grep -rlZ 'TODO' src/ | xargs -0 sed -i 's/TODO/DONE/g'Piping & Combining
<command> | grep '<pattern>' — Filter the output of another command.
ps aux | grep 'nginx'<command> | grep -v 'grep' — Filter output and exclude the grep process itself from results.
ps aux | grep 'nginx' | grep -v 'grep'<command> | grep -c '<pattern>' — Count matching lines from piped input.
cat access.log | grep -c '404'grep '<a>' <file> | grep '<b>' — Chain grep commands to match lines containing both patterns (AND logic).
grep 'ERROR' app.log | grep 'database'<command> | grep -q '<pattern>' && echo 'found' — Quiet mode — suppress output and use exit code in scripts.
grep -q 'root' /etc/passwd && echo 'root user exists'Practical Examples
grep -rn 'TODO\|FIXME\|HACK' src/ — Find all TODO, FIXME and HACK comments in source code with line numbers.
grep -rl 'old_function' src/ | xargs sed -i 's/old_function/new_function/g' — Find and replace a string across all matching files.
grep -oP '(?<=href=")[^"]+' index.html — Extract all URLs from href attributes using PCRE lookbehind.
grep -E '^[0-9]{1,3}(\.[0-9]{1,3}){3}' access.log | sort | uniq -c | sort -rn | head — Count and rank IP addresses in a log file.
grep -Pzo '(?s)<div class="content">.*?</div>' page.html — Match a multiline pattern using PCRE with null-terminated output.
grep -r --include='*.env' -l 'PASSWORD' . — Find environment files that contain password references.
grep -cE '^(import|from)' src/*.py | sort -t: -k2 -rn — Count import statements per Python file, sorted by count.
grep -B2 -A5 'function.*login' auth.js — Show context around a function definition.
zgrep '<pattern>' <file.gz> — Search inside gzip-compressed files without decompressing.
zgrep 'error' /var/log/syslog.2.gzgrep -rn --include='*.{css,scss}' 'z-index' src/ — Find all z-index declarations across CSS and SCSS files.
Conclusion
grep earns its place in your daily workflow by being fast, composable and predictable: pick the right regex flavour (-F for literals, -E for extended, -P for Perl features), add -r to walk directories, and combine -n, -o or -c to shape the output. grep itself only reads – it never changes your files – so the real care lies in what you pipe its results into, for example grep -rlZ … | xargs -0 sed -i …, which edits files in place. Note that -P (PCRE) is a GNU extension and is not available in the BSD/macOS grep; there you install GNU grep (as ggrep) or fall back to -E.
Further Reading
- GNU grep manual – complete reference for options and regex syntax
- Regular-Expressions.info – in-depth tutorial on regex, including PCRE features