Users started reporting failures around lunchtime. The service's log — the file where software writes down everything it does, like a diary — sits at /var/log/api.log, and it is thousands of lines long. Somewhere in there are the lines that explain the problem. Reading the whole thing is not an option; you need the tool that reads it for you.
grep is that tool: it prints only the lines of a file that match a pattern — the word or fragment you are hunting for — and hides everything else. It turns "scroll through forty thousand lines" into "read the twelve that matter".
What grep actually does
The shape is always the same: grep PATTERN FILE — "show me every line of FILE that contains PATTERN". The name is odd but the idea is a needle in a haystack: you describe the needle, and grep hands you every straw that contains one, one line at a time.
grep -i error /var/log/api.log # matching lines, any capitalisation grep -n -i error /var/log/api.log # ...with line numbers grep -v DEBUG /var/log/api.log # everything EXCEPT matches grep -r "TODO" src/ # search every file in a directory grep -C 3 -i error /var/log/api.log # 3 lines of context around each hit
Source: /var/log/api.log (8 of 40,000 lines)
12:41:02 INFO request GET /orders 200 41ms 12:41:03 DEBUG cache hit orders:1041 12:41:07 ERROR db connect timeout (5000ms) 12:41:07 INFO request GET /orders 503 5002ms 12:41:09 WARN retry 1/3 db-01 12:41:14 Error: pool exhausted, dropping request 12:41:14 INFO request GET /health 200 2ms 12:41:15 DEBUG cache miss orders:1042
Output: grep -n -i error /var/log/api.log
3:12:41:07 ERROR db connect timeout (5000ms) 6:12:41:14 Error: pool exhausted, dropping request
-i matched both ERROR and Error; -n added the line numbers so you can jump straight to them.
The letters after the dash are flags — switches that adjust how a command behaves. Five of grep's come up constantly: -i ignores capitalisation, -n adds line numbers, -v inverts the match, -r searches a whole directory, and -C 3 shows three lines of context either side of each hit.
| Flag | What it does | Example |
|---|---|---|
-i | Ignore capitalisation while matching. | grep -i error api.log |
-n | Prefix each matching line with its line number. | grep -n error api.log |
-v | Invert: print the lines that do not match. | grep -v DEBUG api.log |
-r | Recurse: search every file under a directory. | grep -r "TODO" src/ |
-C 3 | Show 3 lines of context before and after each hit. | grep -C 3 -i error api.log |
-c | Count matching lines instead of printing them. | grep -c -i error api.log |
-E | Use extended patterns, for example alternatives. | grep -E -i "error|timeout" api.log |
grep -n -i -C 2 error api.log is line numbers, any capitalisation, two lines of context.The wrong tools people reach for first
Three commands look tempting here, and each teaches the same lesson about picking a tool by its job. cat prints the whole file — all forty thousand lines, and now you are spotting the bad ones by eye. tail shows the end of the file: recent lines, but all of them, and the evidence you need may be from two hours ago. find searches for files by name — a different question entirely; you already know which file, you need what is inside it. grep is the only one whose whole job is "matching lines, nothing else".
The flag that saves the hunt: -i
Here is the trap that catches almost everyone once: software is inconsistent about capital letters. The same log can contain ERROR, Error and error, written by different parts of the system. Without -i, grep matches exactly what you typed and silently misses the rest — half the evidence gone, and nothing tells you it is missing. When you hunt keywords in logs, -i is not optional politeness. It is the habit.
Where you'll meet this on the job
Almost all operational evidence is text — logs, configuration files, code — which is why grep is the most-used investigation command in the shell. It gets stronger when you chain it to other tools with the pipe (|), which feeds one command's output into the next:
tail -f api.log | grep -i error # live errors only, as they happen grep -i error api.log | wc -l # how many? count the matches ps aux | grep nginx # find a running process
That first line is what an engineer's screen looks like during an incident: the log streaming live, filtered to the lines that matter. Small tools, composed — that is the shell's whole philosophy, and grep sits in the middle of it.
One detail worth knowing before it bites: when grep's output goes to your screen it prints each match immediately, but when it goes into another pipe it saves output in a buffer and sends it in blocks. So tail -f api.log | grep -i error | cut -d' ' -f1 can look silent for a while. GNU grep has --line-buffered for exactly this case; add it whenever grep sits in the middle of a live pipeline.