Regular expressions are the grammar behind grep, sed, awk, and most search boxes you have ever used. Learning to read them — before writing them — is the practical path, and it takes one page.

The characters that do work #

Everything in a regex is literal except a small cast:

SymbolMatches
.Any single character
^ / $Start / end of the line
* / + / ?0+, 1+, or optional repeat of the previous
[abc] / [a-z]One character from a set or range
[^abc]One character NOT in the set
(abc)A group, for repeats and capture
`\`Alternation in extended regex
\d \w \sDigit, word char, whitespace (in some tools)

Everything else matches itself. error is a perfectly good regex; so is ^2026-10-2\d.

Reading patterns aloud #

The skill is saying the pattern in words before typing it. Some workhorses:

Patterns you will actually use
^ERROR          lines that START with ERROR
\.log$          lines that END with .log
^[a-z]+@[a-z]+  local-part of simple emails
(timeout|retry) either word
[0-9]{2,4}      two to four digits

Building them is incremental: start with a literal that matches, add one construct, re-test. grep -o shows exactly what matched, which makes each step verifiable:

See precisely what your regex matched
$ grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' access.log | head

The two regex dialects #

grep defaults to basic regular expressions, where +, ?, (, and | need backslashes. Add -E for extended regex and they work bare — the saner dialect, and the reason -E appears throughout this series:

Same search, two dialects
$ grep 'error\(1\|2\)' file.log    # basic
$ grep -E 'error(1|2)' file.log    # extended

For the tools that consume these patterns, continue with sed for editing and grep for filtering — then put the pieces together in unix pipes in practice. The terminal notes series covers each step.