Cheat Sheet

grep Command Examples

grep prints the lines that match a pattern, from files or from whatever you pipe into it. The examples here cover the everyday flags, recursive search, regex, logs and processes, compressed files, and what to use instead on Windows.

Last updated September 11, 2026

Syntax

Options can come before or after the pattern. With more than one file, grep prefixes every output line with the file name.

grep [options] PATTERN [file ...]
Exit codeMeaning
At least one line matched
Nothing matched
An error: missing file, unreadable directory, bad pattern

The Basics

CommandWhat it does
Print lines containing error
Case insensitive (matches Error, ERROR)
Show line numbers
Invert: lines that do NOT match
Count matching lines instead of printing them
Match whole words only (skips passport)
Match whole lines only
Print only the matched text, not the whole line
Stop after the first match
List files that match, not the lines
List files that do NOT match
Fixed string: treat the pattern literally, no regex
Silent; exit code only (for in scripts)
Hide the file name prefix
Force the file name prefix on a single file
Keep the highlighting through a pager

matches each directory's basename, not its path, so one name skips it everywhere in the tree.

CommandWhat it does
Search every file under the current directory
Recursive with file name and line number
Recursive, case insensitive
Just the file names (feeds nicely into xargs)
Only search .py files
Skip minified files
Skip a directory
Skip several directories
Like -r, but also follows symlinks

Multiple Patterns

CommandWhat it does
OR: match either pattern
OR with extended regex
Read patterns from a file, one per line
AND: lines containing both
Match one, exclude another
Exclude several patterns
Count lines matching either
Lines that appear in both files
Lines in new.txt that are not in old.txt

Counting Matches

CommandWhat it does
Count matching lines
Count occurrences, including several per line
Count the lines that do not match
Per-file counts across a tree
Same, hiding files with no matches
Rank the distinct matches by frequency

counts lines, not matches: a line with three hits still counts as one. Use piped into when you need the real total.

Regex

grep's default dialect is basic regex (BRE). Add for extended regex (ERE), where , , , and work without backslashes. works on every grep, including macOS.

PatternMatches
Any single character
Zero or more of the previous item
error at the start of the line
error at the end of the line
Empty lines
Any one of these characters
Any character that is not a digit
Character ranges
, , POSIX classes (portable stand-ins for \d, \s)
A literal dot (escape to match them literally)
Word boundaries (same idea as -w)

With :

PatternMatches
One or more: gogle, google, gooogle
Optional: color and colour
Alternation
Grouping: ab, abab
Repetition counts (start of an IP address)

unlocks Perl regex (, , lookaheads) but only exists in GNU grep. The grep on macOS and BSD does not have it: use with POSIX classes, or and call .

Context Lines

CommandWhat it does
Show 3 lines After each match
Show 3 lines Before each match
3 lines of Context on both sides
Context plus line numbers

Groups of matches are separated by a line. Nearby matches merge into one block.

Pipes and xargs

grep is at its best at the end of a pipe. See the awk cheat sheet for what usually comes after it.

CommandWhat it does
Find a running process (see the ps cheat sheet)
Same, without grep matching its own process line
Just the PIDs of the java processes
The same list without the grep trick
Kill by full command line instead of
Search your shell history
Kernel messages about USB
Which proxy variables are set
Which log files contain error
Find files, then edit them (see the sed cheat sheet)
Safe with spaces in file names (see the find cheat sheet)

Searching Logs

CommandWhat it does
The everyday log sweep
Each error plus the lines under it
Live tail, filtered (without output stalls)
Filter a unit's journal (see the journalctl cheat sheet)
Docker sends some logs to stderr, so redirect first
Same idea for a Kubernetes deployment
One morning's lines, by timestamp prefix

For a real range between two timestamps, is the better tool. See the awk cheat sheet.

Compressed Files

CommandWhat it does
Search a gzipped file without unpacking it
Rotated logs, plain and gzipped in one pass
Count inside a compressed file
The same thing by hand
bzip2 archives
xz archives
Stream a tarball's contents through grep (see tar)
Search the text inside a zip

takes the same flags as grep, so , and all carry over.

grep on Windows

Windows has no grep built in, but both shells have an equivalent.

CommandWhat it does
cmd: basic search
cmd: case insensitive, recursive (roughly )
cmd: invert, like
cmd: regex, in findstr's own limited dialect
PowerShell: the real grep equivalent, full regex
PowerShell: grep is case sensitive by default, Select-String is not
PowerShell: recursive search
PowerShell: sls is the short alias

Git Bash and WSL both ship genuine GNU grep, so works there unchanged.

Alternatives to grep

grep is on every machine you will ever log into. These are faster in a large source tree, but you have to install them first.

CommandWhat it does
ripgrep: recursive by default and skips anything in .gitignore
Case insensitive, limited to Python files
Turn the .gitignore and hidden-file filtering back off
Search only tracked files, from anywhere in the repo (see git)
Search every commit in the history
The Silver Searcher, the same idea as ripgrep
GNU grep on macOS, after

Gotchas

  • is GNU-only. On macOS, fails with "invalid option"; use or install GNU grep (, then ).
  • Always quote the pattern. Unquoted, the shell expands and against your files before grep ever sees them.
  • grep exits 1 when nothing matches. In a script with that kills the script; append when no-match is fine.
  • In basic regex, and are literal characters. matches the literal text go+gle; you want .
  • "Binary file matches" means the file has non-text bytes. forces it to be treated as text, and skips binary files entirely during a recursive search.
  • with no file name is not hung, it is waiting on standard input. Ctrl+C out, then give it a file or a pipe.
  • A file written on Windows ends each line with a carriage return, so finds nothing. Run on it first.
  • works, but is one process instead of two and lets grep print the file name.
  • grep finds lines, sed edits them, and awk works on columns. The three cover most text jobs between them.

grep FAQ

Why is the grep command called grep?

It is the name of a command in the old Unix line editor ed: g/re/p, which reads as "globally search for a regular expression and print the matching lines". Ken Thompson split that out into a standalone program in the early 1970s and the name stuck, first as a command and then as a verb. The behavior still matches the name, which is why grep prints whole lines by default and needs -o to print only the matched text.

Is the grep command case sensitive?

Yes, by default. -i turns that off for the whole pattern, so grep -i error also matches Error and ERROR. When you only want part of the pattern relaxed, use a character class instead: grep -E "[Ee]rror: [0-9]+" keeps the digits strict. Case folding also follows your locale, so LC_ALL=C grep -i runs faster on large files but stops folding accented characters.

Can the grep command be used with glob characters?

Not in the pattern. grep patterns are regular expressions, so * means "zero or more of the previous character" and ? is a literal question mark in the default dialect. The glob equivalent of * is .* in regex. Globs do work in the file list (grep error *.log, expanded by the shell before grep runs) and in --include and --exclude, which match shell-style globs against file names.

Why is my grep command not working?

Four usual causes. The pattern was unquoted and the shell expanded it first. The pattern uses + or ?, which are literal characters until you add -E. The file came from Windows, so every line ends in a carriage return and anchors like error$ never match until you run dos2unix on it. Or the file is binary, so grep only prints "Binary file matches" until you add -a. "grep: command not found" is a different problem: the shell cannot find grep at all, which on Windows means you are not in Git Bash or WSL.

Does Windows have a grep command?

There is no grep binary. cmd has findstr (findstr /S /I "error" *.log is roughly grep -ri), which works but has a narrow regex dialect; use /C:"two words" when the pattern contains spaces, since findstr otherwise treats each word as a separate pattern. PowerShell's Select-String is much closer to grep and takes full .NET regex, but it returns match objects, so pipe it through ForEach-Object Line when a script wants plain text. Git for Windows and WSL both ship genuine GNU grep.

Related cheat sheets