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.

grep '<pattern>' <file> — Search for a pattern in a file and print matching lines.

grep 'error' /var/log/syslog

grep '<pattern>' <file1> <file2> — Search for a pattern in multiple files.

grep 'TODO' app.js utils.js

grep -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/syslog

grep -w '<pattern>' <file> — Match whole words only (not substrings).

grep -w 'error' app.log

grep -x '<pattern>' <file> — Match entire lines only.

grep -x 'OK' status.txt

Regular Expressions

grep -E '<pattern>' <file> — Use extended regular expressions (ERE) — supports +, ?, |, () without escaping.

grep -E 'error|warning|fatal' app.log

grep -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.log

grep -F '<string>' <file> — Treat the pattern as a fixed string, not a regex (faster for literal matches).

grep -F '$(document).ready' app.js

grep -E '^<pattern>' <file> — Match lines starting with a pattern.

grep -E '^#' config.ini

grep -E '<pattern>$' <file> — Match lines ending with a pattern.

grep -E '\.js$' filelist.txt

grep -E '<a>|<b>' <file> — Match lines containing either pattern (alternation).

grep -E 'GET|POST' access.log

grep '\.<ext>' <file> — Escape special regex characters with backslash for literal match.

grep 'version 2\.0' changelog.txt

Output Control

grep -n '<pattern>' <file> — Show line numbers alongside matching lines.

grep -n 'function' app.js

grep -c '<pattern>' <file> — Count the number of matching lines.

grep -c 'ERROR' app.log

grep -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/*.js

grep -o '<pattern>' <file> — Print only the matched part of each line, not the entire line.

grep -oE '[0-9]+\.[0-9]+\.[0-9]+' version.txt

grep -H '<pattern>' <file> — Always print the filename with each match.

grep -Hn 'error' *.log

grep -h '<pattern>' <files> — Suppress filenames in output when searching multiple files.

grep -h 'export' src/*.js

grep --color=always '<pattern>' <file> — Highlight matches in color (useful when piping through less).

grep --color=always 'error' app.log | less -R

Context Lines

grep -A <n> '<pattern>' <file> — Show n lines after each match.

grep -A 3 'Exception' error.log

grep -B <n> '<pattern>' <file> — Show n lines before each match.

grep -B 5 'FATAL' error.log

grep -C <n> '<pattern>' <file> — Show n lines before and after each match (context).

grep -C 2 'segfault' /var/log/kern.log

Inverting & Filtering

grep -v '<pattern>' <file> — Invert match — print lines that do not match the pattern.

grep -v '^#' config.ini

grep -v -e '<a>' -e '<b>' <file> — Exclude lines matching any of several patterns.

grep -v -e '^#' -e '^$' config.ini

grep -e '<a>' -e '<b>' <file> — Match lines containing any of multiple patterns.

grep -e 'error' -e 'warning' app.log

grep -f <patternfile> <file> — Read patterns from a file (one pattern per line).

grep -f keywords.txt document.txt

Recursive 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.bin

grep -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.gz

grep -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

  • sed – stream editor for transforming the lines grep finds
  • awk – field-aware processing and reporting on matched lines
  • find – locate files by name and metadata, then hand them to grep