Course outline · 0% complete

0/29 lessons0%

Course overview →

grep from zero

lesson 4-1 · ~9 min · 10/29

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:

FlagNameEffect
-iignore casemilk also matches Milk and MILK
-nline numbersPrefixes each match with its line number
-vinvertPrints the lines that do not match
-ccountPrints 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
2

The 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.