Regular expressions (regex) describe text patterns. On a server, they’re how you find the interesting lines in huge logs, extract IP addresses, validate input, and edit config files with one command. The core syntax is small. Once you know a dozen symbols, you can read most patterns.

Not to be confused with shell wildcards (*.log). See wildcards and globbing.

The essentials

Pattern Meaning Example match
abc Literal text abc
. Any single character a.c → abc, a-c
^ Start of line ^Error
$ End of line \.conf$
[abc] One of these characters gr[ae]y
[^abc] Any character except these [^0-9]
[a-z0-9] Ranges [0-9]
* Previous item 0+ times ab*c → ac, abbbc
+ 1+ times (ERE) [0-9]+
? 0 or 1 time (ERE) colou?r
{n,m} Between n and m times (ERE) [0-9]{1,3}
( ) Group (ERE) (GET|POST)
| Alternation: either side (ERE) error|fail
\ Escape a special character \. matches a dot

Character classes: [[:digit:]], [[:alpha:]], [[:space:]], [[:alnum:]]. In PCRE: \d (digit), \w (word character), \s (whitespace), \b (word boundary).

BRE, ERE and PCRE

Linux tools speak slightly different dialects:

Dialect Used by Note
BRE (basic) grep, sed by default + ? | ( ) { } need a backslash: \+, \(, \{
ERE (extended) grep -E, sed -E, awk + ? | ( ) { } work directly
PCRE grep -P, Perl, Python, PHP, most languages Adds \d, \w, lookarounds, non-greedy *?

Tip: use grep -E and sed -E to avoid backslash soup.

grep examples

grep -E 'error|fail|critical' /var/log/syslog
grep -Ei 'timeout' app.log                      # case-insensitive
grep -Ec '" 5[0-9]{2} ' access.log              # count 5xx responses
grep -Ev '^\s*(#|$)' /etc/ssh/sshd_config       # config without comments and blank lines
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' auth.log | sort | uniq -c | sort -rn | head   # IPs
grep -P 'user=\w+' app.log

See grep command examples.

sed examples

sed -E 's/^#?PermitRootLogin .*/PermitRootLogin no/' -i /etc/ssh/sshd_config
sed -E 's/listen [0-9]+;/listen 8080;/' nginx.conf
sed -E 's/(\w+)@example\.com/\[email protected]/g' users.txt      # \1 = first group
sed -n -E '/^\[mysqld\]/,/^\[/p' /etc/mysql/my.cnf            # print a section

Test without -i first. Check the output, then apply. See sed command examples.

awk examples

awk '$9 ~ /^5/ {print $7}' access.log | sort | uniq -c | sort -rn | head    # URLs returning 5xx
awk '/Failed password/ {print $(NF-3)}' /var/log/auth.log | sort | uniq -c | sort -rn

See awk command examples.

Useful patterns for server work

Purpose Pattern (ERE)
IPv4 address (rough) ([0-9]{1,3}\.){3}[0-9]{1,3}
HTTP status in an Nginx log " [0-9]{3}
ISO date [0-9]{4}-[0-9]{2}-[0-9]{2}
Email (rough) [A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}
Blank or comment line ^\s*(#|$)
Trailing whitespace [[:space:]]+$

“Rough” patterns are fine for searching logs. Validating input (emails, IPs) properly needs stricter rules, or library functions.

Common pitfalls

  • Unescaped dots: example.com also matches exampleXcom. Use example\.com.
  • Greedy matching: ".*" matches from the first quote to the last one on the line. Use "[^"]*" instead (or .*? in PCRE).
  • Shell quoting: wrap regexes in single quotes, so the shell doesn’t interpret $, * or \.
  • Dialect mix-ups: \d doesn’t work in grep -E. Use [0-9], or grep -P.

Quick reference

Need Syntax
Start / end of line ^ / $
Any character .
Repeat * + ? {n,m}
Alternatives a|b (ERE)
Group and reuse ( ) and \1
Extended mode grep -E, sed -E

Related: find and rename files and pipes and redirection.

  • Linux
  • Regex
  • Command Line