open atlas
↑ Back to track
Command line CLI · 04 · 03

Searching content with grep

grep searches file contents for a pattern. -r searches a whole directory tree; -n shows line numbers; -i ignores case; -l lists only matching filenames; --include limits the search to specific file types.

CLI Junior ◷ 20 min
Level
FoundationsJuniorMiddleSenior

find locates files by metadata — name, size, age. But what if you need to find files by what is inside them? Which source file calls getUserById? Which config file sets MAX_CONNECTIONS? That is grep’s job: it reads file contents line by line and prints every line that matches a pattern.

By the end of this lesson you will search entire directory trees for text patterns, control output format, and use basic regular expressions with grep.

Goal

After this lesson you can run grep -r to search a directory tree for a pattern, add -n for line numbers, -i for case-insensitive matching, -l to list only matching filenames, and --include to restrict the search to specific file extensions. You can also write simple regular expressions for grep.

1

Basic grep: pattern then file(s). grep prints every line in the file(s) that contains the pattern:

grep "error" app.log           # lines containing "error" in app.log
grep "TODO" src/main.ts        # lines containing TODO in one file
grep "timeout" *.conf          # search all .conf files in current dir

The pattern is a Basic Regular Expression (BRE) by default. For Extended Regular Expressions (ERE) add -E; for Perl-compatible regexes add -P.

2

-r searches a directory tree recursively. This is the flag you will use most often in day-to-day work:

grep -r "getUserById" src/       # search every file under src/
grep -r "MAX_CONNECTIONS" /etc/  # search all config files under /etc

Output format is filename:line content. grep follows symlinks with -r only when -R (uppercase) is used on GNU grep; -r does not follow symlinks by default.

3

-n, -i, -l control output format.

  • -n — prefix each matching line with its line number:
grep -rn "panic" ./logs/     # grep -r -n combined; shows file:linenum:line
  • -i — case-insensitive matching. Matches Error, error, ERROR:
grep -ri "error" src/
  • -l — list only the filenames of files that contain a match (suppresses the lines themselves). Useful when you just want to know which files are affected:
grep -rl "deprecated" src/     # which files mention "deprecated"?

These flags compose freely: grep -rnil "TODO" . is perfectly valid.

4

--include and --exclude narrow the file set. Without them, -r searches every file including binaries. The --include glob is matched against the filename:

grep -r "import" src/ --include="*.ts"      # only TypeScript files
grep -r "password" . --include="*.{yml,yaml,json}"  # config files only
grep -r "debug" . --exclude="*.min.js"      # skip minified JS files

The glob in --include is processed by grep, not the shell — quote it to be safe.

5

Basic regular expressions in grep. grep patterns are not plain strings — they are BRE by default:

MetacharMeaningExample
.any single charactergr.p matches grep, grap, gr9p
*zero or more of the previouserr.*or matches error, err0r, errXXXXor
^start of line^import matches lines that begin with import
$end of line};$ matches lines that end with };
[...]character class[Ee]rror matches Error or error
\bword boundary (GNU)\berror\b matches error not errors

Use -F (fixed string) when you want no regex interpretation at all — fastest option for plain text searches.

grep -rn "^import " src/ --include="*.ts"    # lines starting with "import "
grep -rF "process.exit(1)" .                 # literal string, no regex
Worked example

Finding all usages of a deprecated function in a TypeScript project.

You need to find every call to legacyFetch so you can replace it:

grep -rn "legacyFetch" src/ --include="*.ts"

Sample output:

src/api/users.ts:14:  const data = await legacyFetch('/users');
src/api/posts.ts:8:   return legacyFetch('/posts/' + id);
src/utils/http.ts:3:  export function legacyFetch(url: string) {

Three files, with line numbers. Now list just the filenames to plan the refactor:

grep -rl "legacyFetch" src/ --include="*.ts"
src/api/users.ts
src/api/posts.ts
src/utils/http.ts

Pipe to wc -l to count how many files are affected:

grep -rl "legacyFetch" src/ --include="*.ts" | wc -l
3
Why this works

BSD grep (macOS) vs GNU grep (Linux). They share the same core flags (-r, -n, -i, -l), but differ in details:

  • --include and --exclude work on both, but --include-dir is GNU-only.
  • -P (Perl-compatible regex) is GNU-only; BSD grep does not support it. Use -E (ERE) for portable extended patterns.
  • Color output (--color=auto) works on both but the default differs.

For scripts that must run on macOS, use only BRE/ERE (-E) and avoid -P. Or install GNU grep via Homebrew (brew install grep) and invoke it as ggrep.

Common mistake

Using grep -r on a large tree without --include hits binary files and is slow. grep will try to read every file — compiled binaries, images, .git objects. Add --include to restrict to text file extensions, and add --exclude-dir=.git to skip version control objects:

# Slow and noisy: binary matches show as "Binary file X matches"
grep -r "config" .

# Fast and clean
grep -r "config" . --include="*.{ts,js,json,yml}" --exclude-dir=.git
Check yourself
Quiz

You want to find which files under src/ contain the word 'TODO', searching only .ts files, without printing the matching lines — just the filenames. Which command is correct?

Recap

grep pattern file(s) prints every line that matches the pattern. -r extends the search recursively through a directory tree; -n adds line numbers; -i makes matching case-insensitive; -l prints only filenames. --include="*.ext" narrows the search to specific file types — always use it with -r to avoid scanning binaries and .git. grep patterns are Basic Regular Expressions by default; add -E for extended syntax or -F for literal fixed-string matching.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 4 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.