Linux Basic — POSIX Character Classes
POSIX Character Classes
\d, \w, \s are Perl-style. They don’t work in BRE, ERE, awk, or Bash =~. The portable equivalents are POSIX character classes: [[:digit:]], [[:alpha:]], etc.
They’re more verbose but they work everywhere a POSIX regex engine runs — and they’re locale-aware, so [[:alpha:]] matches accented letters in en_US.UTF-8 while [A-Za-z] does not.
The Full List
| Class | Equivalent (ASCII) | Matches |
|——-|———————|———|
| [[:alpha:]] | [A-Za-z] | letters |
| [[:digit:]] | [0-9] | digits |
| [[:alnum:]] | [A-Za-z0-9] | letters + digits |
| [[:upper:]] | [A-Z] | upper-case |
| [[:lower:]] | [a-z] | lower-case |
| [[:space:]] | [ \t\n\r\f\v] | whitespace |
| [[:blank:]] | [ \t] | space or tab only |
| [[:punct:]] | [!-/:-@\[-{-~] | punctuation |
| [[:xdigit:]] | [0-9A-Fa-f] | hex digit |
| [[:cntrl:]] | control chars | non-printable |
| [[:print:]] | printable + space | opposite of cntrl |
| [[:graph:]]` | printable, not space | visible chars |
Syntax — Note the Double Brackets
A character class lives inside a bracket expression. So a regex character class needs two sets of brackets:
# match one digit
grep -E '[[:digit:]]' # correct
grep -E '[:digit:]' # WRONG — matches one of : d i g t
You can combine multiple classes and literals inside the outer brackets:
# identifier: starts with letter/underscore, then letters/digits/underscore
grep -E '^[[:alpha:]_][[:alnum:]_]*$'
Quantify Them
# 4+ uppercase letters
grep -E '[[:upper:]]{4,}'
# whitespace-tolerant key=value
grep -E '^[[:alnum:]_]+[[:space:]]*=[[:space:]]*.+$'
# trim leading whitespace with sed
sed -E 's/^[[:space:]]+//'
Negate a Class
Put ^ after the outer [:
# anything that's NOT a digit
grep -E '[^[:digit:]]'
# strip non-alphanumerics
sed -E 's/[^[:alnum:]]+/_/g'
Why Prefer POSIX Classes Over [A-Z0-9]?
- Portable. Works in
grep,sed,awk, Bash=~, plus other Unix tools — without escaping or-Equirks. - Locale-aware. In a UTF-8 locale
[[:alpha:]]includesé,ñ,ü.[A-Za-z]does not. - Self-documenting.
[[:xdigit:]]reads as “hex digit”;[0-9A-Fa-f]does not.
When you need ASCII-only matching regardless of locale, set the locale explicitly:
LC_ALL=C grep -E '[[:alpha:]]+' input
LC_ALL=C also makes grep/sort dramatically faster on ASCII data.
Bash =~ with POSIX Classes
Same syntax, no surprises:
if [[ "$word" =~ ^[[:alpha:]][[:alnum:]_]*$ ]]; then
echo "valid identifier"
fi
Cheat-Sheet
| You want… | Use |
|---|---|
| Digit | [[:digit:]] |
Word char (letter+digit+_) |
[[:alnum:]_] (POSIX has no \w) |
| Whitespace | [[:space:]] |
| Non-whitespace | [^[:space:]] |
| Hex | [[:xdigit:]] |
| Printable, no space | [[:graph:]] |
Next → sed Regex in Scripts