Searching with grep
Learn to search file contents with grep — the fastest way to find which files contain a pattern, on what line, and in what context.
What you'll learn
- Run grep to find lines matching a pattern in one file or an entire directory tree
- Use essential flags: -i, -r, -n, -w, -v, -c, -l, -o, and -A/-B/-C
- Pass grep a piped stream and write basic regex patterns with -E
Before you start
What grep does
grep reads lines of text and prints only the ones that match a pattern — a string or a regular expression you supply. Think of it as a filter: every line goes in, only matching lines come out.
input lines ──► [ grep PATTERN ] ──► matching lines
Basic syntax
grep PATTERN file
Search config.py for the string API_KEY:
grep API_KEY config.py
API_KEY = "abc123"
You can search multiple files at once by listing them or using a glob:
grep API_KEY config.py settings.py
grep API_KEY *.py
Essential flags
-n — show line numbers
Tells you exactly where the match lives. Almost always useful.
grep -n API_KEY config.py
14:API_KEY = "abc123"
-i — case-insensitive
Matches api_key, API_KEY, Api_Key, etc.
grep -i api_key config.py
-r / -R — recursive through a directory
This is the answer to the opening question. Search every file under src/:
grep -r API_KEY src/
src/config.py:14:API_KEY = "abc123"
src/utils/auth.py:3:API_KEY = os.environ.get("API_KEY")
-r follows symbolic links on most systems; -R always does on GNU grep.
-l — list filenames only
When you only need to know which files match, not the lines themselves:
grep -rl API_KEY src/
src/config.py
src/utils/auth.py
-c — count matching lines per file
grep -rc API_KEY src/
src/config.py:1
src/utils/auth.py:1
src/tests/test_auth.py:0
-w — whole word
Without -w, grep error matches errors, errored, and fatal_error. With -w it only matches the standalone word error.
grep -w error app.log
-v — invert (lines that do NOT match)
Invert flips the filter: print every line that does not match the pattern. Handy for stripping comments or blank lines.
grep -v "^#" config.ini
That ^# is a tiny regex — ^ anchors to the start of the line, so this removes lines that begin with #.
-o — print only the matching part
Instead of the whole line, emit just the text that matched:
grep -o "API_KEY" config.py
API_KEY
More useful combined with regex (shown below).
-A, -B, -C — context lines
Real errors don’t exist in isolation. Context flags print surrounding lines so you can see what caused a match.
| Flag | Meaning |
|---|---|
-A N | N lines After the match |
-B N | N lines Before the match |
-C N | N lines before and after (Context) |
grep -C 2 "TypeError" app.log
Traceback (most recent call last):
File "app.py", line 42, in process
result = int(value)
TypeError: int() argument must be a string
During handling of the above exception:
Reading from a pipe
grep works seamlessly in a pipeline. The command to the left produces lines; grep filters them.
ps aux | grep nginx
root 1234 0.0 nginx: master process
www-data 1235 0.1 nginx: worker process
cat app.log | grep -i "error"
You can chain multiple greps to narrow results further:
grep -r "def " src/ | grep -v "test_"
This finds all function definitions except those in test files.
A gentle intro to regex in grep
grep patterns are regular expressions — a mini-language for describing text shapes. You don’t need to learn all of it now. Here are the most useful pieces:
| Pattern | Matches |
|---|---|
. | any single character |
^foo | lines that start with foo |
foo$ | lines that end with foo |
[aeiou] | any one vowel |
[0-9] | any digit |
To use extended regex (which adds +, ?, \d, \w, and more), pass -E:
grep -E "[0-9]{4}" data.txt
port: 8080
year: 2026
[0-9]{4} matches exactly four consecutive digits.
grep -E "^(ERROR|WARN)" app.log
Matches lines that begin with either ERROR or WARN.
Putting it all together
Back to the opening question — 400 files, find every mention of API_KEY with line numbers:
grep -rn API_KEY .
./src/config.py:14:API_KEY = "abc123"
./src/utils/auth.py:3:API_KEY = os.environ.get("API_KEY")
./docs/setup.md:22:export API_KEY=your_key_here
Three files, three lines, under a second. That’s grep.