grep across many files
Real projects are hundreds of files. Questions like "where is this function used?" or "which files still say TODO?" can't be answered one file at a time — and this is the search that working engineers run many times a day (every editor's project-wide search box is a version of it). grep has flags for exactly this:
grep -r pattern directory: recursive — search every file in the directory and all its subdirectories. Each match prints aspath:matching line, so you know which file it came from.grep -rn pattern .: add line numbers too;path:line:textis the exact address of every match.grep -rl pattern .: print only the list of file names that contain a match, one per line — for when the question is "which files", not "which lines".
Code exercise · bash
Run it. We build a tiny project with a TODO note in two different files, then one grep -rn finds both without being told where to look. (The | sort makes the order predictable — grep visits files in whatever order the filesystem returns them.)
Patterns, not just words
The pattern you give grep is not plain text — it's a regular expression (regex for short): a small language for describing the shape of text. So far you've used the boring subset, where letters match themselves. Four symbols unlock the useful subset:
| symbol | matches |
|---|---|
^ | the start of the line |
$ | the end of the line |
. | any single character |
[abc] | one character from the set |
So ^error matches lines that begin with error (not lines that merely mention it), and full$ matches lines that end with full. Quote the pattern — grep '^error' file — so the shell passes it to grep untouched, the same reason find's pattern was quoted in lesson 4-2.
Regular expressions go much deeper (they deserve a course of their own), but ^ and $ alone sharpen a large share of real searches.
Code exercise · bash
Run it. A plain `grep error` would match three of these lines. Anchoring with ^ keeps only the lines that START with error, and full$ finds the one line that ENDS with full.
Quiz
In a grep pattern, what does `^` mean?
Code exercise · bash
Your turn. The starter writes a 5-line events.log. Print every line that STARTS with `user`, then print how many lines END with `ok` (lesson 4-1's -c counts matches). Expected output: ``` user alice logged in user bob logged in 2 ```