| title | Linux Command Tutorial: grep | ||||
|---|---|---|---|---|---|
| date | 2026-09-12 00:00:00 +0000 | ||||
| categories |
|
||||
| tags |
|
||||
| draft | false | ||||
| slug | linux-grep-tutorial | ||||
| description | Authoritative reference tutorial for grep (GNU Grep), detailing regular expression engines (BRE, ERE, PCRE), recursive search, performance optimization, and POSIX portability. | ||||
| upstream_suite | gnu-grep | ||||
| upstream_version | GNU Grep 3.11 | ||||
| posix_standard | POSIX.1-2024 | ||||
| research_date | 2026-09-12 |
The Linux Command Tutorial series provides rigorous, upstream-verified references for essential system commands across Linux distributions and UNIX-like environments. Each article focuses on a single executable, combining exhaustive option documentation, verified real-world examples, security boundaries, and best practices directly derived from official source documentation and POSIX standards.
Upstream:
GNU Grep 3.11| POSIX:POSIX.1-2024 (with GNU extensions)| Safety Tier:safe-read-only| Scope:Fast pattern search, regex filtering & stream line extraction
grep searches input files for lines matching one or more regular expression patterns. It utilizes the Boyer-Moore fast string search algorithm alongside deterministic finite automata (DFA) regex engines, streaming matching lines to standard output.
- Upstream Project & Provenance: Developed and maintained under GNU Grep (
grep). - Portability & Standards Baseline: Standardized in IEEE Std 1003.1-2024 (POSIX.1-2024). GNU
grepincorporates Perl-Compatible Regular Expressions (-P), context controls (-A,-B,-C), recursive directory searches (-r,-R), and color highlighting. - Target Research Implementation: Audited against GNU Grep 3.11 (
grep(1)). - Applicability & Lifecycle: The standard text filtering utility for shell pipelines, log analysis, and source code navigation.
grep [OPTION...] PATTERNS [FILE...]
grep [OPTION...] -e PATTERNS ... [FILE...]
grep [OPTION...] -f PATTERN_FILE ... [FILE...]GNU grep supports four distinct regex matching engines:
- Basic Regular Expressions (BRE, default or
-G): Standard POSIX syntax; special characters like(,),{,},+,?require backslash escaping to function as operators. - Extended Regular Expressions (ERE,
-Eoregrep): Metacharacters like(,),{,},+,?,|are operators by default. - Fixed Strings (
-Forfgrep): Treats patterns as exact literal strings; disables regex evaluation for maximum performance. - Perl-Compatible Regular Expressions (PCRE,
-P): Full Perl 5 regex syntax, including lookaheads(?=...), lookbehinds(?<=...), non-greedy quantifiers.*?, and character classes\d,\s,\w.
| Short Flag | Long Flag | Description | POSIX Defined |
|---|---|---|---|
-E |
--extended-regexp |
Interpret PATTERNS as extended regular expressions (ERE). | Yes |
-F |
--fixed-strings |
Interpret PATTERNS as fixed strings (no regex). | Yes |
-P |
--perl-regexp |
Interpret PATTERNS as Perl-compatible regular expressions. | No |
-i |
--ignore-case |
Ignore case distinctions in patterns and input data. | Yes |
-v |
--invert-match |
Invert the sense of matching, to select non-matching lines. | Yes |
-w |
--word-regexp |
Select only those lines containing matches that form whole words. | No |
-x |
--line-regexp |
Select only those matches that exactly match the whole line. | Yes |
| Short Flag | Long Flag | Description | POSIX Defined |
|---|---|---|---|
-n |
--line-number |
Prefix each line of output with the 1-based line number. | Yes |
-c |
--count |
Suppress normal output; print a count of matching lines. | Yes |
-l |
--files-with-matches |
Print only names of FILEs with matching lines. | Yes |
-L |
--files-without-match |
Print only names of FILEs with no matching lines. | No |
-o |
--only-matching |
Print only the matched (non-empty) parts of a matching line. | No |
-q |
--quiet, --silent |
Quiet mode: suppress all output; exit immediately with 0 if match found. | Yes |
-r |
--recursive |
Read all files under each directory recursively; follow symlinks only on command line. | No |
-R |
--dereference-recursive |
Recursively search directories, following all symbolic links. | No |
| Short Flag | Long Flag | Description | Default |
|---|---|---|---|
-A NUM |
--after-context=NUM |
Print NUM lines of trailing context after matching lines. | 0 |
-B NUM |
--before-context=NUM |
Print NUM lines of leading context before matching lines. | 0 |
-C NUM |
--context=NUM |
Print NUM lines of leading and trailing output context. | 0 |
| Task / Scenario | Command | Key Flags / Behavior |
|---|---|---|
| Case-insensitive search | grep -i "error" app.log |
-i matches upper and lower case |
| Show matching line numbers | grep -n "listen" nginx.conf |
-n prefixes 1-based line numbers |
| Invert match (exclude lines) | grep -v "^#" config.conf |
-v selects lines that do NOT match |
| Only print matched substring | grep -E -o "[0-9]{1,3}\.[0-9]{1,3}..." log |
-o outputs matched token per line |
| Count matching lines | grep -c "404" access.log |
-c prints count instead of lines |
| Fast literal search | grep -F "192.168.1.1" access.log |
-F disables regex for maximum speed |
| Recursive search with line numbers | grep -rn "API_KEY" ./src |
-r recursive search; -n line numbers |
| Show lines with context | grep -B 2 -A 3 "FATAL" error.log |
-B before lines; -A after lines |
| Quiet check (for if statements) | if grep -q "root" /etc/passwd; then ... |
-q exits 0 on first match, no output |
grep -i "error" /var/log/nginx/error.loggrep -n "listen" /etc/nginx/nginx.confSample terminal output:
38: listen 80 default_server;
39: listen [::]:80 default_server;
Extracting only IPv4 addresses from an access log:
grep -E -o "([0-9]{1,3}\.){3}[0-9]{1,3}" /var/log/nginx/access.log | head -n 3Sample terminal output:
192.168.1.45
10.0.0.12
172.16.5.99
- Technical Analysis:
-ostrips everything else on the line, outputting each regex match on its own dedicated newline.
Viewing 2 lines before and 3 lines after a database connection error:
grep -B 2 -A 3 "FATAL: connection refused" /var/log/postgresql/postgresql.logSample terminal output:
2026-09-12 11:20:00 [4123] LOG: starting background worker
2026-09-12 11:20:01 [4123] LOG: connecting to primary node
2026-09-12 11:20:02 [4123] FATAL: connection refused
2026-09-12 11:20:02 [4123] DETAIL: target server unreachable at port 5432
2026-09-12 11:20:02 [4123] LOG: worker process exited with code 1
2026-09-12 11:20:03 [4123] LOG: retrying in 5 seconds
grep -rn --exclude-dir=".git" --exclude-dir="node_modules" "API_KEY" ./src- Traverses
./srcrecursively, printing file names and line numbers while skipping bulky vendor and version control trees.
When searching for exact strings (no regex metacharacters), -F achieves significantly higher throughput:
grep -F "user_id_482918" /data/event_stream.json- Bypasses regex compilation and uses Boyer-Moore pattern matching.
Extracting values between JSON quotes using PCRE lookbehind and lookahead assertions:
echo '{"status": "healthy", "uptime": 86400}' | grep -P -o '(?<="status": ")[^"]*'Sample terminal output:
healthy
Testing if a user exists in /etc/passwd without output:
if grep -q "^deploy:" /etc/passwd; then
echo "User deploy exists"
fi- Halts reading immediately upon the first match, avoiding processing the remainder of the file.
| Exit Code | Meaning |
|---|---|
0 |
Selected lines were found (at least one match). |
1 |
No lines were selected (pattern not found). |
>1 |
An error occurred (file unreadable, syntax error in pattern). |
In UTF-8 locales (en_US.UTF-8), range expressions like [a-z] sort according to dictionary collation order rather than ASCII byte offsets, which can match capital letters. To enforce strict ASCII byte ranges:
LC_ALL=C grep "[a-z]" fileSetting LC_ALL=C also dramatically boosts search performance (often by 500%+) on ASCII text by avoiding multi-byte character validation.
Warning
Infinite Symlink Recursion Hazard: The uppercase -R (--dereference-recursive) flag instructs grep to follow all symbolic links to directories. If a codebase or log directory contains circular symlinks (e.g. dir/link -> ..), grep -R enters an infinite loop, exhausting memory and file descriptors.
Always prefer lowercase -r (--recursive), which traverses child subdirectories without dereferencing directory symlinks.
Tip
In UTF-8 locales (en_US.UTF-8), range expressions like [a-z] sort according to dictionary collation order rather than ASCII byte offsets. Prefixing large log scans with LC_ALL=C enforces direct byte matching, typically boosting throughput by 300% to 500%:
LC_ALL=C grep "[a-z]" large_archive.log-
Use
-Ffor Literal String Searches:[!TIP] Guidance: When searching for static strings containing dots, brackets, or slashes (e.g. URLs or IPs), pass
-F. Authoritative Justification: GNU documentation notes that fixed-string search avoids regex compilation overhead and prevents metacharacter interpretation errors. -
Prefix Automated Checks with
grep -q:[!TIP] Guidance: Use
grep -qin shell conditional statements (if grep -q ...). Authoritative Justification: Terminates input processing upon the first matching line and avoids polluting terminal streams. -
Use
LC_ALL=Cfor Massive Log Scans:[!TIP] Guidance: Prefix large log searches with
LC_ALL=C grep .... Authoritative Justification: Bypasses UTF-8 multi-byte decoding, yielding substantial throughput gains.
- GNU Grep Manual: https://www.gnu.org/software/grep/manual/grep.html
- POSIX.1-2024 grep Specification: The Open Group Base Specifications Issue 8. https://pubs.opengroup.org/onlinepubs/9799919799/utilities/grep.html