grep searches text with patterns and prints the matching lines. It is the backbone of every "where did this error come from?" moment, and it shines brightest inside pipes where other commands feed it.
The basic search #
$ grep error app.log
app.log:42:2026-10-21T09:12:01Z error: connection refused
app.log:77:2026-10-21T09:13:44Z error: timeout
By default grep treats the pattern literally. The output prefixes each match with its file and line number — that number is your navigation into the file.
The flags that matter #
| Flag | Behaviour |
|---|---|
-i | Case-insensitive match |
-n | Show line numbers |
-r | Search directories recursively |
-v | Invert: show lines that do not match |
-c | Count matching lines instead of printing them |
-l | List only the names of files with matches |
-w | Match whole words only |
-E | Extended regular expressions, enabling alternation |
Real patterns #
Search a whole project, case-insensitively, with context:
$ grep -rni -A2 -B2 "todo" src/
Count failures across kinds with an extended expression:
$ grep -cE "error|fatal" app.log
Everything except comments and blank lines — the classic config-file view:
$ grep -vE '^\s*(#|$)' /etc/ssh/sshd_config
In pipes #
grep is built for pipelines: filter the output of any command by feeding it in.
$ ps aux | grep nginx
See ps for what the left side produces, and find when the search target is file names rather than file contents.
More search-and-filter notes land in the journal as part of the terminal notes series.
