Regular Expressions in Bash
Prerequisites: File and string tests, Searching text with grep
Inside [[ ]], the =~ operator matches a string against an extended
regular expression, and captures matching groups into the
BASH_REMATCH array — no external tools needed.
Validating and extracting
re='^([a-z0-9._%+-]+)@([a-z0-9.-]+\.[a-z]{2,})$'
for email in "ada@example.com" "not-an-email" "linus@kernel.org"; do
if [[ $email =~ $re ]]; then
echo "$email → user: ${BASH_REMATCH[1]}, domain: ${BASH_REMATCH[2]}"
else
echo "$email → invalid"
fi
done
ada@example.com → user: ada, domain: example.com
not-an-email → invalid
linus@kernel.org → user: linus, domain: kernel.org
BASH_REMATCH[0]is the whole match;[1],[2], ... are the groups in parentheses.- Store the regex in a variable and use it unquoted (
=~ $re). Quoting the right side makes Bash treat it as plain text, not a pattern.
Parsing structured strings
version="v2.14.3-beta"
if [[ $version =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)(-(.+))?$ ]]; then
major=${BASH_REMATCH[1]}
minor=${BASH_REMATCH[2]}
patch=${BASH_REMATCH[3]}
tag=${BASH_REMATCH[5]:-none}
echo "major=$major minor=$minor patch=$patch tag=$tag"
echo "next minor: v$major.$(( minor + 1 )).0"
fi
major=2 minor=14 patch=3 tag=beta
next minor: v2.15.0
Log lines
line='192.168.1.20 - - [22/Apr/2025:09:12:30] "GET /api/orders HTTP/1.1" 500 1234'
re='^([0-9.]+) .*"([A-Z]+) ([^ ]+) [^"]*" ([0-9]{3})'
if [[ $line =~ $re ]]; then
printf 'ip=%s method=%s path=%s status=%s\n' "${BASH_REMATCH[@]:1:4}"
fi
ip=192.168.1.20 method=GET path=/api/orders status=500
Build and test patterns in the Regex Tester —
Bash uses POSIX extended regular expressions, which don't support
shortcuts like \d (use [0-9]).
When to use what
[[ =~ ]]— checking or parsing one string inside a script.grep -E/sed -E/awk— processing many lines of a file, where they're much faster than a Bash loop.