grep: finding lines
The command you will type most in your life: grep prints the lines of a file, or of a pipe, that contain a pattern.
What you will learn
- Search one or several files for a word and read grep's output.
- Use grep as a filter at the end of a pipe.
- Quote patterns correctly and use grep's exit status to answer yes/no questions.
grep PATTERN FILE reads the file line by line and prints every line that contains the pattern. That is the whole idea. The name comes from the old ed editor command g/re/p — globally search for a regular expression and print — and the regular-expression part is where its power comes from, but you can get a long way treating the pattern as plain text. This lesson does exactly that; lessons 33 and 34 add the regex syntax.
One file, several files
With a single file, grep prints the matching lines as they are. With several files, or a wildcard like *.txt, it prefixes each line with the file name and a colon, so you know where each hit came from. -h hides that prefix and -H forces it even for a single file. The match is case-sensitive and happens anywhere in the line: grep cat matches concatenate.
~% cd /root/lab/l31
l31% cat fruits.txt
apple
banana
grape
pineapple
cherry
l31% grep apple fruits.txt
apple
pineapple
l31% grep an fruits.txt notes.txt
fruits.txt:banana
notes.txt:bananas are cheap
l31% grep /bin/false /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/bin/false
bin:x:2:2:bin:/bin:/bin/false
sys:x:3:3:sys:/dev:/bin/false
mail:x:8:8:mail:/var/spool/mail:/bin/false
www-data:x:33:33:www-data:/var/www:/bin/false
operator:x:37:37:Operator:/var:/bin/false
nobody:x:65534:65534:nobody:/home:/bin/false
grep in a pipe
Given no file, grep reads stdin, which makes it the universal filter: ls /bin | grep grep lists the commands whose name contains grep, ps | grep sh shows the shells running, history | grep ssh finds that command you typed last week. Any output that is too long to read becomes manageable once you grep it for the piece you care about.
Quote the pattern
The shell processes the command line before grep sees it. A pattern with a space would be split into two arguments, * would expand to file names, and $ would start a variable. Wrap patterns in single quotes whenever they contain anything other than letters and digits: grep 'No such file' log.txt. It costs nothing when the quotes were unnecessary and saves you from strange errors when they were.
The exit status
grep exits with 0 when it found at least one match, 1 when it found none, and 2 on an error such as a missing file. That turns it into a test: grep -q root /etc/passwd && echo 'root exists'. The -q (quiet) option prints nothing and stops at the first match, which is exactly what you want when only the yes/no answer matters. You will use this constantly in scripts.
| Form | Output |
|---|---|
grep word file | matching lines |
grep word f1 f2 | file:line for each match |
cmd \| grep word | matching lines of cmd's output |
grep -q word file | nothing; exit 0 if found, 1 if not |
Commands in this lesson
| Command | What it does |
|---|---|
grep PATTERN file | Print lines of file containing PATTERN. |
grep PATTERN f1 f2 | Search several files; output is prefixed with the file name. |
cmd | grep PATTERN | Filter another command's output. |
grep 'two words' file | Quote patterns with spaces or special characters. |
grep -q PATTERN file | Print nothing; succeed only if there is a match. |
grep -h PATTERN f1 f2 | Several files without the name prefix. |
Quiz
What does `grep cat animals.txt` print?
- Only lines that are exactly `cat`
- Every line that contains `cat` anywhere, such as `concatenate`
- The number of lines containing cat
When does grep prefix each line with a file name?
- Always
- When searching more than one file (or with -H)
- Only when reading from a pipe
What is the exit status of grep when it finds no match?
- 0
- 1
- 2
Why should you write `grep 'No such file' log.txt` with quotes?
- Because grep requires quotes around every pattern
- Because without them the shell would split the pattern into three arguments
- Because log.txt contains spaces
Practice
/root/lab/l31/fruits.txt lists fruits, one per line. Save every line that contains `apple` into /root/lab/l31/apples.txt.
Which accounts in /etc/passwd have `/bin/false` as their shell? Save the matching lines into /root/lab/l31/false.txt.
Using a pipe, list the commands in /bin whose name contains `grep`.
Open this lesson in the app to do the tasks in a real Linux machine and have them checked.