Literal match — the simplest case:
grep "error" logfile.txtFinds every line containing the word "error".
. (dot) matches any single character:
grep "c.t" file.txt # matches: cat, cut, cot, c@t, c1t ...[ ] character class matches one character from a set:
grep "c[aou]t" file.txt # matches: cat, cot, cut — but NOT cit
grep "[0-9]" file.txt # any line with a digit
grep "[a-zA-Z]" file.txt # any line with a letter[^ ] negated class — match anything not in the set:
grep "[^0-9]" file.txt # lines with any non-digit characterAnchors don't match characters — they match positions.
grep "^error" file.txt # lines that START with "error"
grep "done$" file.txt # lines that END with "done"
grep "^$" file.txt # empty lines (start immediately followed by end)These attach to the character or group before them.
| Pattern | Meaning |
|---|---|
* |
0 or more times |
+ |
1 or more times (use grep -E) |
? |
0 or 1 time (use grep -E) |
{n} |
exactly n times (use grep -E) |
{n,m} |
between n and m times (use grep -E) |
grep "lo*l" file.txt # ll, lol, lool, loool ...
grep -E "lo+l" file.txt # lol, lool ... (at least one 'o')
grep -E "colou?r" file.txt # color OR colour
grep -E "[0-9]{3}" file.txt # any 3 consecutive digits
grep -Eenables Extended Regex (ERE), which unlocks+,?,{n}, and|. You can also useegrepas a shorthand.
grep -E "cat|dog" file.txt # lines with "cat" OR "dog"
grep -E "error|warn|critical" app.logParentheses group patterns together:
grep -E "(ha)+" file.txt # ha, haha, hahaha ...
grep -E "(192\.168\.)" ip_list.txtNote: . inside a class [.] or escaped \. becomes a literal dot.
Special chars (. * + ? [ ] ^ $ ( ) | \ { }) need a backslash to be treated literally:
grep "3\.14" file.txt # literal "3.14", not "3X14"
grep "\$PATH" file.txt # literal "$PATH"| Flag | What it does |
|---|---|
-i |
Case-insensitive match |
-v |
Invert — show lines that do not match |
-n |
Show line numbers |
-c |
Count matching lines |
-r |
Recursive search in directories |
-l |
Only print filenames with matches |
-o |
Print only the matched part, not the whole line |
-E |
Extended regex (+, ?, |, {}) |
grep -in "warning" app.log # case-insensitive, with line numbers
grep -v "^#" config.txt # hide comment lines
grep -rn "TODO" ./src # find all TODOs in source code
grep -E -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" access.log # extract IPs# Find lines with an email-like pattern
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" contacts.txt
# Find lines with a 4-digit year
grep -E "\b(19|20)[0-9]{2}\b" file.txt
# Find function definitions in Python
grep -E "^def [a-zA-Z_]+" *.py
# Find HTTP error codes in a log
grep -E "\" [45][0-9]{2} " access.log
# Show non-empty, non-comment lines in a config
grep -Ev "^#|^$" /etc/ssh/sshd_configThink of a regex as reading left to right: "match this, then that, then this many of those." Start simple — get a literal match working, then add anchors, then quantifiers.
Use -o to see exactly what you're matching when debugging a pattern.