Linux/Mac Terminal Tutorial: The Grep Command - Search Files and Directories for Patterns of Text
Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Use grep to search for a pattern in a specific file and print matching lines directly in the terminal.
Briefing
Grep is a fast way to search for text patterns across files and directories from the Linux or Mac terminal, and mastering its options turns a simple “find this word” task into practical debugging and code-navigation work. At its core, grep scans files for lines that match a pattern and prints the matching lines—so the immediate payoff is knowing exactly where a string appears, not just that it exists.
A basic workflow starts with searching a single file. For example, running grep with a pattern like “John Williams” against names.txt returns every line containing that text. Grep is case-sensitive by default, which means “john” and “John” won’t match unless case-insensitive mode is enabled. The -i flag fixes that by matching regardless of letter case.
When partial matches are a problem, grep’s -w option helps enforce whole-word matching. That’s useful when searching for a full name but avoiding near-matches like “John Williamson” when only “John Williams” should count. Once matches are found, additional flags add the context people usually need for follow-up work. The -n option prints line numbers, making it easier to jump straight to the exact location in a file. For context around a match, grep supports several “window” options: -B shows lines before the match, -A shows lines after, and -C shows both sides (with a configurable number of lines). This is especially handy when searching source code, because the surrounding lines often reveal what the match refers to.
Grep becomes more powerful when applied to multiple files. Using a wildcard like * with grep lets it search everything in the current directory, while adding a file extension filter such as *.txt limits results to text files. If the goal is to search through an entire project—including subdirectories—grep’s -r recursive option is the standard approach. That said, recursion can be slow in large directory trees, so it’s worth being deliberate about where the search starts.
For large codebases, many users don’t need the matching lines themselves; they need to know which files contain the pattern. The -l option lists only filenames with matches, and -c reports how many matches each file contains. These switches help triage quickly before opening files.
Finally, grep’s pattern matching can go beyond plain text into regular expressions. By default, grep uses POSIX regular expressions, but Perl-compatible regular expressions (PCRE) require different handling—especially on macOS. On Linux, the -P option enables PCRE directly. On macOS, grep is typically BSD grep, so PCRE support may not work as expected; the workaround is installing GNU grep via Homebrew (brew install grep) so that -P behaves correctly. With GNU grep in place, PCRE features like \\d with quantifiers can be used to find phone-number-like patterns, and the same combination of -w, -i, -r, and -l can be layered on to search recursively and report only the relevant files.
Cornell Notes
Grep searches files for lines matching a text pattern and prints the results, making it a go-to tool for locating information in terminal workflows. Key options include -w for whole-word matches, -i for case-insensitive search, and -n for line numbers. Context flags (-B, -A, -C) show surrounding lines so matches can be understood in code or logs. Grep scales from single files to directories using wildcards and -r for recursive searches, while -l and -c help summarize results by filename or match count. For advanced pattern matching, grep supports regular expressions; on macOS, PCRE often requires installing GNU grep via Homebrew to use -P reliably.
How do -w and -i change what grep returns when searching names or other exact strings?
What combination of flags helps someone quickly locate and interpret a match inside a file?
Why does grep fail when given a directory path directly, and how do wildcards and -r fix it?
When searching many files, how can you reduce noise by reporting only filenames or counts?
What’s the difference between POSIX regex and PCRE in grep, and why does macOS require extra steps?
How can you search for phone-number-like patterns using PCRE with grep?
Review Questions
- When would you choose -w over a plain grep search, and what kind of false matches does it prevent?
- How do -B, -A, and -C differ in the context they print around a match?
- What steps are needed on macOS to reliably use PCRE features with grep’s -P option?
Key Points
- 1
Use grep to search for a pattern in a specific file and print matching lines directly in the terminal.
- 2
Apply -w for whole-word matching to avoid partial hits like “John Williamson” when searching for “John Williams.”
- 3
Add -i for case-insensitive searches when capitalization varies across files.
- 4
Use -n for line numbers and -B/-A/-C to print surrounding context so matches can be understood in situ.
- 5
Search multiple files with wildcards (e.g., * or *.txt) and search entire projects with -r, but expect long runtimes in large directory trees.
- 6
For large result sets, use -l to list only filenames with matches and -c to count matches per file.
- 7
On macOS, PCRE support may require installing GNU grep via Homebrew so that -P works for patterns like digit-based phone-number expressions.