Recall from lesson 3-1 that cat prints an entire file to the terminal at once.
That works fine for a shopping list, but reading a 10,000-line file by eye to locate one word is not a strategy. This lesson introduces the tool that does the reading for you: grep.
grep: find lines that match
Here is a week-one engineering task. A service misbehaves, the log file is 80,000 lines, and the one line you need contains the word "error". Scrolling will not get you there. This is the problem grep was built for, and it is why grep is among the most-used commands in existence.
grep pattern file reads the file and prints only the lines containing the pattern. That is the entire idea.
grep milk shopping.txt
The flags that come up constantly:
| Flag | Name | Effect |
|---|---|---|
-i | ignore case | milk also matches Milk and MILK |
-n | line numbers | Prefixes each match with its line number |
-v | invert | Prints the lines that do not match |
-c | count | Prints how many lines matched instead of the lines |
By default grep is case-sensitive, and nearly every beginner loses ten minutes to that at least once. The example below lets you watch it happen harmlessly.
Case sensitivity, caught in the act
The first grep misses Milk shake because of its capital M. Adding -i catches both spellings.
echo "milk" > list.txt echo "bread" >> list.txt echo "Milk shake" >> list.txt echo "coffee beans" >> list.txt grep milk list.txt grep -i milk list.txt
Output
milk milk Milk shake
Counting the output lines tells the story. The first grep produced one line, the second produced two, and the pattern and file were identical in both. Case sensitivity was the only difference.
Line numbers, counts, and inverted matches
The remaining flags applied to a file of numbers: -n reports where matches are, -c counts them, and -v flips the filter to keep non-matching lines. The | head part trims the long output of -v down to three lines, and that | pipe is unit 5's topic.
seq 1 20 > nums.txt grep -n 7 nums.txt grep -c 1 nums.txt grep -v 1 nums.txt | head -n 3
Output
7:7 17:17 11 2 3 4
Two output lines deserve decoding. 7:7 means line 7 contains the match 7, with the number before the colon being the location and the text after it being the line. And grep -c 1 reports 11 because it counts every line containing the digit 1, which is 1 itself plus each of 10 through 19.
To get every line of config.txt that does not contain the word "disabled", the command is grep -v disabled config.txt. The -v flag inverts the match, so grep keeps precisely the lines that fail the pattern.
Neither neighbor does this job. -i only changes whether case matters, and -c would collapse the result to a single number instead of printing the lines you want to read.
Combining flags handles the common log-triage pair: list the problems, then count them. Here a four-line log is built with mixed capitalization, grep -i error finds both spellings, and adding -c to the same command reports how many there were.
echo "error: disk full" > app.log echo "info: started" >> app.log echo "ERROR: no network" >> app.log echo "info: retrying" >> app.log grep -i error app.log grep -c -i error app.log
Output
error: disk full
ERROR: no network
2The count agrees with the listing, which is a useful sanity check. Both error: and ERROR: matched thanks to -i, the two info: lines were filtered out, and the trailing 2 is the same result expressed as a number rather than as text.