Skip to content
Latchkey

grep Anchors and Character Classes Basics

grep anchors ^ and $ match the start and end of a line, while [...] matches any one character from a set.

Tighter patterns mean fewer false positives in CI gates. Anchors and character classes are the building blocks that make a grep precise.

What it does

In a grep pattern, ^ matches the start of a line and $ matches the end, so ^ERROR$ matches a line that is exactly "ERROR". [abc] matches any one of a, b, or c; [^abc] matches any character except those; ranges like [0-9] and [A-Za-z] work too. POSIX classes such as [[:digit:]] and [[:space:]] are portable equivalents.

Common usage

Terminal
# lines that are exactly "PASS"
grep '^PASS$' results.txt

# lines starting with a timestamp
grep '^[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}' app.log

# POSIX class: any line with a digit
grep '[[:digit:]]' versions.txt

Options

TokenMatches
^Start of line
$End of line
[abc] / [^abc]Any one (or any not) of the set
[0-9] / [a-z]A character range
[[:digit:]] [[:space:]]POSIX character classes

In CI

Anchor status assertions with ^...$ so a partial line cannot pass the gate. Prefer POSIX classes like [[:digit:]] over [0-9] when locale or portability matters, and remember that in basic regex {n} needs backslashes (\{n\}) while in -E it does not.

Common errors in CI

In basic (default) grep, { } ( ) + ? are literal unless escaped, so ^[0-9]{4} does not mean four digits without -E or \{4\}. CRLF input breaks $ anchoring because the \r sits before the line end; strip it with tr -d "\r". A [a-z] range can behave by locale; set LC_ALL=C for byte-wise, predictable matching in CI.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →