Vol. I · No. 46The command line sectionSat, 10 Oct 2026
Linux · reading files

grep

find the lines that match

grep reads its input line by line and prints only the lines that contain the pattern. The pattern can be a plain word or a regular expression, and the input can be a file, a whole directory tree, or the output of another command.

A log has ten thousand lines; grep hands you the twelve that matter.

Prints
Matching lines
the whole line, not just the word
Pattern
Text or regex
case-sensitive unless -i
Input
Files or a pipe
command | grep pattern
Exit status
0 if found
1 if nothing matched

At the terminal

Read the session first, then the notes: each numbered line in the output is answered by the note with the same number.

user@netflow — bashgrep
$ grep -n "error" app.log
114:2026-09-30 10:02:11 error: connection refused
57:2026-09-30 10:19:43 error: timeout after 30s
2$ grep -ic "ERROR" app.log
5
3$ grep -rn "TODO" src/
src/app.py:42: # TODO: handle timeout
src/db/pool.py:9:# TODO: make size configurable
4$ ps aux | grep -v grep | grep nginx
root 812 0.0 0.1 55180 1692 ? Ss 09:00 0:00 nginx: master process /usr/sbin/nginx
Illustrative session · names, sizes and dates are examples, and every address is from a documentation or private range
Reading the output

What the numbered lines are telling you

1
-n puts the line number first

Line 14 and line 57 of app.log contain "error". The search is case-sensitive, so "Error" and "ERROR" were not matched.

2
-i ignores case, -c counts

Switches can be joined: -ic is -i and -c. Five lines match once upper and lower case are treated alike — three more than before.

3
-r searches a whole tree

Every file under src/ is read. Each match is prefixed with the file it was found in, then the line number.

4
Filtering another command’s output

The pipe feeds ps into grep. -v inverts a match: it drops the line for the grep process itself, which would otherwise match "nginx" too.

Switches

A switch changes how the command behaves. These are the ones used day to day; man grep lists the rest. Single-letter switches can usually be joined, so -l -a may be written -la.

-i
Ignore case: match upper and lower case alike.
-v
Invert: print the lines that do not match.
-n
Prefix each match with its line number.
-r
Recursive: search every file under a directory.
-c
Count: print how many lines matched, not the lines themselves.
-l
List only the names of the files that contain a match.
-w
Match whole words only, so "log" does not match "login".
-E
Extended regular expressions: |, + and ? work without backslashes.
-A NUM
Also print NUM lines after each match. -B is before, -C is both.
-o
Print only the part of the line that matched.

Variations worth knowing

The same tool, pointed at a narrower question. These four cover most of what it is reached for day to day.

grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"

Shows a configuration file without its comments and blank lines.

grep -rl "password" /etc 2>/dev/null

Lists only the names of the files that mention a word.

grep -E "error|warn|fail" app.log

Matches any of several words, using an extended regular expression.

grep -C 2 "timeout" app.log

Prints two lines of context before and after each match.

In cybersecurity

grep is how logs are read in practice — by defenders looking for an intrusion and by intruders looking for secrets.

Hunting through logs

"grep 'Failed password' /var/log/auth.log" lists failed SSH logins; piping it on to sort and uniq -c shows which addresses are guessing.

Finding secrets left in files

A recursive grep for "password", "secret" or "BEGIN PRIVATE KEY" is the first thing run on a compromised host — and worth running on your own code before it is published.

A pattern is not a filter you can trust

A check built on grep can be dodged by different case, spacing or encoding. Good for finding things; weak as a security control.

Filed under

Reading files

Read alongside