Finding Text: grep
grep prints every line that contains a word or phrase, in one file, in many files or in a whole folder, and its options ignore capitals, number the lines, list only the files that match, count the matches or show the lines that don't match.
Apprentice · Unix · Linux · Updated
After this lesson you can
- Search files for a word or phrase with grep, using -i, -n and -r
- Choose -l, -c or -v to list the matching files, count matching lines or show the lines that don't match
Key takeaways
- grep, a word, then files prints every line that contains the word. With several files, each line starts with its file's name.
- grep is case-sensitive. -i ignores capitals, -n numbers the lines, and -r searches a folder and every folder inside it.
- -l lists only the files that match, -c counts the matching lines in each file, and -v shows the lines that don't match.
- Put a phrase with spaces in quotes, and always name a file or folder. Without one, grep waits for you to type.
Your landlord says the June rent never arrived. Somewhere in a folder of 300 saved emails is the bank's receipt with payment number 4471, and opening them one at a time would take all evening. A file manager's search may find the right file, but it won't show you the line. grep reads every line of every file you point it at and prints the ones that contain your words, in about a second. IT techs use it to search logs when something breaks in the night, and developers use it to find every place a word appears in a project.
Set up the archive's door logs
The town archive from Terminal Quest (you'll play it at the end of this lesson) records every badge that opens one of its doors. Here is one week of its records to practice on: a staff list and one file per day. Copy these lines into your terminal. They make the folder ~/terminal-practice/archive and are safe to run again.
mkdir -p ~/terminal-practice/archive/logs && cd ~/terminal-practice/archive
printf 'BADGE NAME JOB\n2041 Imani Osei archivist\n3317 Rosa Lind cleaner\n5520 Sam Okafor night guard\n6188 Lee Park librarian\n9050 Ines Duarte visiting researcher\n' > staff.txt
printf '09:02 door=west badge=6188 in\n17:15 door=west badge=6188 out\n19:20 door=east badge=3317 in\n20:45 door=east badge=3317 out\n21:04 door=front badge=5520 in\n23:31 door=reading-room badge=5520 check\n' > logs/2026-11-02.log
printf '09:05 door=west badge=6188 in\n10:30 door=front badge=9050 in\n14:12 door=map-room badge=2041 in\n16:40 door=front badge=9050 out\n19:18 door=east badge=3317 in\n20:50 door=east badge=3317 out\n21:02 door=front badge=5520 in\n' > logs/2026-11-03.log
printf '09:01 door=west badge=6188 in\n19:25 door=east badge=3317 in\n20:47 door=east badge=3317 out\n21:06 door=front badge=5520 in\n23:40 note: East door was open. Closed it.\n' > logs/2026-11-04.log
printf '10:15 door=front badge=9050 in\n13:30 door=reading-room badge=9050 in\n19:21 door=east badge=3317 in\n20:44 door=east badge=3317 out\n21:03 door=front badge=5520 in\n22:58 door=east badge=9050 out\n23:35 NOTE: east door open again!\n' > logs/2026-11-05.log
printf '09:04 door=west badge=6188 in\n19:19 door=east badge=3317 in\n20:46 door=east badge=3317 out\n21:05 door=front badge=5520 in\n23:30 note: east door locked all night.\n' > logs/2026-11-06.log
ls logs
2026-11-02.log 2026-11-03.log 2026-11-04.log 2026-11-05.log 2026-11-06.log
Each file is a log file: a file that gets one new line every time something happens. Here a line is a time, a door, a badge number and in or out, and now and then a note from the night guard. Computers keep hundreds of logs like these, and they're far too long to read from top to bottom.
grep: every line with a word
The archivist says the east door was found open twice this week. Who uses it? grep (read "grep"; the name comes from an old editor command, short for globally search for a regular expression and print) takes the word to look for, then the file to look in:
grep "door=east" logs/2026-11-05.log
19:21 door=east badge=3317 in
20:44 door=east badge=3317 out
22:58 door=east badge=9050 out
Three of the file's seven lines. Name more files, or use * (read "star") for every file in the folder, and each line starts with the name of the file it came from, then a colon:
grep "door=east" logs/*
logs/2026-11-02.log:19:20 door=east badge=3317 in
logs/2026-11-02.log:20:45 door=east badge=3317 out
logs/2026-11-03.log:19:18 door=east badge=3317 in
logs/2026-11-03.log:20:50 door=east badge=3317 out
logs/2026-11-04.log:19:25 door=east badge=3317 in
logs/2026-11-04.log:20:47 door=east badge=3317 out
logs/2026-11-05.log:19:21 door=east badge=3317 in
logs/2026-11-05.log:20:44 door=east badge=3317 out
logs/2026-11-05.log:22:58 door=east badge=9050 out
logs/2026-11-06.log:19:19 door=east badge=3317 in
logs/2026-11-06.log:20:46 door=east badge=3317 out
Badge 3317 every evening, and once, late on the 5th, badge 9050. grep 9050 staff.txt answers whose that is: 9050 Ines Duarte visiting researcher. In Ubuntu's terminal the words that matched show in red.
Two habits save trouble. Put the words in quotes when they hold a space ("east door"), so grep gets them as one search. And always name a file or a folder: without one, grep waits for you to type instead. If that happens, press Ctrl+C to get your prompt back.
Capitals and line numbers: -i and -n
Now look for the guard's notes about the door:
grep "east door" logs/*
logs/2026-11-05.log:23:35 NOTE: east door open again!
logs/2026-11-06.log:23:30 note: east door locked all night.
Only two, but the door was open twice. grep is case-sensitive: to it, E and e are different letters, so East door on the 4th doesn't match. -i (for ignore case) treats capitals and small letters as the same:
grep -i "east door" logs/*
logs/2026-11-04.log:23:40 note: East door was open. Closed it.
logs/2026-11-05.log:23:35 NOTE: east door open again!
logs/2026-11-06.log:23:30 note: east door locked all night.
-n (for number) puts each line's number in front of it, so you can find it in the file:
grep -n 9050 logs/2026-11-05.log
1:10:15 door=front badge=9050 in
2:13:30 door=reading-room badge=9050 in
6:22:58 door=east badge=9050 out
A whole folder: -r and -l
-r (for recursive) searches a folder, every file in it, and every folder inside it, however deep. . (read "dot") is the folder you're in:
grep -r 9050 .
./staff.txt:9050 Ines Duarte visiting researcher
./logs/2026-11-05.log:10:15 door=front badge=9050 in
./logs/2026-11-05.log:13:30 door=reading-room badge=9050 in
./logs/2026-11-05.log:22:58 door=east badge=9050 out
./logs/2026-11-03.log:10:30 door=front badge=9050 in
./logs/2026-11-03.log:16:40 door=front badge=9050 out
grep goes through a folder in the order the disk keeps the files, not alphabetically, so yours may come in a different order. When the answer is 400 lines long, you often want only the files they're in. -l (for list) prints each file's name once:
grep -rl 9050 .
./staff.txt
./logs/2026-11-05.log
./logs/2026-11-03.log
Options combine, as they do for ls: -rl is -r and -l together, and -ri searches a folder ignoring capitals.
Counting, and the opposite: -c and -v
-c (for count) prints how many lines match in each file, instead of the lines:
grep -c "door=east" logs/*
logs/2026-11-02.log:2
logs/2026-11-03.log:2
logs/2026-11-04.log:2
logs/2026-11-05.log:3
logs/2026-11-06.log:2
The 5th stands out with one extra. -v (for invert) does the opposite of a search: it prints every line that does not match. Every door line has door= in it, so leaving those out shows only the notes:
grep -rv "door=" logs
logs/2026-11-04.log:23:40 note: East door was open. Closed it.
logs/2026-11-05.log:23:35 NOTE: east door open again!
logs/2026-11-06.log:23:30 note: east door locked all night.
These results come from Ubuntu's grep. On a Mac, grep takes the same options and finds the same lines.
Try it in the terminal
Terminal Quest: The Archive, goals 1 to 3: played right on the lesson page.
The Star Map is missing from the archive. Read the archivist's notice, search a whole month of door logs for the map room, and find out whose badge opened it.
Check yourself
2 questions to try on the lesson page.
So what
Any question that starts with "which file says…" or "when did…" is one grep away, however many files there are.