grep is a command-line utility that searches input text line by line for a pattern and prints every line that matches, making it the standard tool for finding strings in files, logs, and the output of other commands. It accepts plain strings or regular expressions, reads from files or from a pipe, and offers flags to control case sensitivity, recursion, context, and output. Mastering grep is one of the highest-leverage skills for working efficiently in a terminal.
Key takeaways
- grep prints lines that match a pattern from files or piped input.
- The pattern can be a fixed string or a regular expression, in basic or extended syntax.
- Core flags include
-ifor case-insensitive,-rfor recursive,-nfor line numbers, and-vto invert the match. - Context flags
-A,-B, and-Cshow lines around each match. - grep shines in pipelines, filtering the output of other commands.
- Quote patterns and anchor them carefully to avoid shell expansion and unintended matches.
What does grep do and how do I run it?
At its core, grep takes a pattern and one or more inputs, then prints the lines containing the pattern. The basic form names the pattern first and the file second:
grep "timeout" server.log
This prints every line in server.log that contains the substring timeout. You can search multiple files at once, and grep will prefix each matching line with the filename so you know where it came from. If you provide no file, grep reads from standard input, which is what makes it so useful in pipelines.
The name comes from an old editor command meaning globally search for a regular expression and print, which precisely describes its behavior.
Which grep flags do developers use most?
A handful of options cover the majority of everyday searches:
-imakes the match case-insensitive.-nprefixes each match with its line number.-ror-Rsearches directories recursively.-vinverts the match, printing lines that do not match.-cprints a count of matching lines instead of the lines.-lprints only the names of files that contain a match.-wmatches only whole words.-oprints only the matched portion rather than the whole line.
These combine freely. For example, grep -rin "TODO" src searches the src directory recursively, ignoring case, and shows line numbers, a common way to find leftover TODO markers in a codebase.
How do I search directories recursively?
To search an entire project tree rather than a single file, use recursive mode with a directory argument:
grep -rn "getUser" .
This walks the current directory and all subdirectories, printing matches with their file paths and line numbers. When a project has directories you want to skip, such as dependency or build folders, exclude them:
grep -rn --exclude-dir=node_modules "getUser" .
You can also restrict to certain file types with --include, for example --include=*.js. Recursive grep is often the fastest way to locate where a function or string is defined and used across a repository, though specialized code-search tools may be faster on very large trees.
What is the difference between basic, extended, and fixed patterns?
grep interprets your pattern as a regular expression by default, but which regex dialect and whether it is a regex at all depend on the mode.
| Mode | Flag | Pattern is treated as |
|---|---|---|
| Basic regex | default | Basic regular expression |
| Extended regex | -E |
Extended regular expression |
| Fixed string | -F |
Literal text, no regex |
| Perl-compatible | -P where supported |
Perl-compatible regular expression |
In basic mode, some metacharacters like + and ? must be escaped with a backslash, whereas extended mode treats them as special directly. The historical commands egrep and fgrep are equivalent to grep -E and grep -F respectively and are now considered deprecated in favor of the flags. Use -F when searching for text that contains regex characters you want taken literally, such as an IP address or a path.
How do I show context around matches?
Seeing only the matching line is often not enough when reading logs. Context flags print surrounding lines:
-A nshowsnlines after each match.-B nshowsnlines before each match.-C nshowsnlines before and after.
grep -n -C 3 "Exception" app.log
This prints each line containing Exception along with three lines on either side and the line numbers, which is invaluable for understanding a stack trace or the events leading up to an error. When matches are close together, grep separates distinct context blocks so you can tell them apart.
How do I use grep in pipelines?
grep is most powerful when it filters the output of another command through a pipe. Instead of a filename, the data arrives on standard input:
ps aux | grep node
This lists processes and keeps only lines mentioning node. You can chain multiple greps to narrow further, and use -v to remove noise:
history | grep git | grep -v status
A classic gotcha is that grep itself can appear in the results of a process search because it is running with that pattern in its arguments. A common trick to avoid this is bracketing the first character of the pattern, as in grep "[n]ode", which matches the target processes but not the grep command line. Quoting patterns also prevents the shell from expanding characters like * before grep ever sees them.
What are common grep pitfalls?
A few recurring issues catch people off guard:
- Unquoted patterns: the shell may expand or split a pattern containing spaces or special characters. Always quote patterns.
- Forgetting it is line-oriented: grep matches within a line, so multi-line patterns need different tools or options.
- Regex versus literal confusion: characters like
.and*are regex metacharacters; use-For escape them when searching for literal text. - Case sensitivity: matches are case-sensitive by default; add
-iwhen case should not matter. - Binary files: grep may report a match in binary files without showing content; use
-ato treat them as text or-Ito skip them. - Searching huge trees blindly: exclude vendored and build directories to keep results relevant and fast.
With patterns quoted, the right regex mode chosen, and context flags to aid reading, grep handles the vast majority of text-search needs directly from the command line.
How can I make grep output more useful?
Beyond finding lines, grep can shape its output to feed other tools or to answer questions directly. A few combinations are worth memorizing.
- Count occurrences per file:
grep -rc "pattern" .prints each file with its match count, handy for spotting hotspots. - List only matching filenames:
grep -rl "pattern" .is ideal when you want to open the files rather than read the lines. - Extract just the match:
grep -ocombined with a regex pulls out specific tokens, such as all email-like strings, one per line. - Number the lines:
grep -ngives you jump targets your editor can use.
grep also sets an exit status you can use in scripts: it returns success when at least one line matched and failure when nothing matched. That makes it a clean test in shell conditionals, for example checking whether a config file already contains a setting before appending it. When you only need the yes-or-no answer and not the output, add -q to run quietly and rely on the exit status alone.
For very large codebases, remember grep reads files sequentially; if searches feel slow, narrow the scope with --include and --exclude-dir, or reach for a purpose-built code search tool. grep remains the portable default that exists on virtually every system.
Frequently asked questions
What is grep used for?
grep searches text for lines matching a pattern and prints them, making it the standard tool for finding strings in files, logs, and command output.
What does grep stand for?
grep derives from a command in older line editors meaning globally search a regular expression and print, which is exactly what it does.
How do I search recursively with grep?
Use the recursive flag, commonly written as grep -r or grep -R, followed by a directory to search all files within it.
What is the difference between grep, egrep, and fgrep?
egrep enables extended regex, equivalent to grep -E, and fgrep treats the pattern as a fixed string, grep -F. The separate commands are deprecated in favor of the flags.
How do I make grep case-insensitive?
Add the -i flag, so grep -i error matches error, Error, and ERROR regardless of case.
How do I show lines around a match?
Use context flags: -A for lines after, -B for lines before, and -C for lines both before and after each match.
How do I use grep with a pipe?
Send another command’s output into grep with a pipe, such as ps aux | grep node, to filter that output to matching lines.