Bash Regex Matching

Bash's =~ operator enables regex matching within [[ ]] conditionals.

Advantage over grep/rg: Better performance for small data - avoids process spawning overhead.

Syntax

if [[ $string =~ regex_pattern ]]; then
    # Match found
fi

Key Points

Regex Type: POSIX Extended Regular Expressions (ERE)

Not Supported: GNU extensions (\b, \s, \d)

Captures: Stored in BASH_REMATCH array

  • [0] = full match
  • [1], [2]... = capture groups

Quoting: Never quote the regex

[[ $str =~ ^[0-9]+$ ]]     # ✓ Works
[[ $str =~ "^[0-9]+$" ]]   # ✗ Treated as literal

POSIX Character Classes

[[:digit:]]   # Instead of \d
[[:space:]]   # Instead of \s
[[:alnum:]]   # Alphanumeric
[[:alpha:]]   # Letters only

Examples (Increasing Difficulty)

# 1. Exact match
[[ "hello" =~ ^hello$ ]]
# Matches exact string "hello"

# 2. Contains pattern
[[ "test123" =~ [0-9] ]]
# Checks if string contains any digit

# 3. One or more digits (+)
[[ "42" =~ ^[0-9]+$ ]]
# Matches strings with only digits (at least one)

# 4. Zero or more characters (*)
[[ "v1.2" =~ ^v[0-9]+\.[0-9]*$ ]]
# Matches "v1.2", "v1.", "v123.456" (optional digits after dot)

# 5. Optional pattern (?)
[[ "color" =~ ^colou?r$ ]]
# Matches both "color" and "colour"

# 6. File extension check
[[ "script.sh" =~ \.(sh|bash)$ ]]
# Matches files ending in .sh or .bash

# 7. Extract with captures
version="v2.4.1-beta"
[[ $version =~ ^v([0-9]+)\.([0-9]+)(\.([0-9]+))?(-(.+))?$ ]]
# Captures: major=2, minor=4, patch=1, tag=beta

# 8. IP address validation
ip="192.168.1.1"
[[ $ip =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]
# Basic IP format check (doesn't validate ranges)

# 9. Parse log entry
log="2024-01-15 14:30:22 ERROR: Connection failed"
regex="^([0-9-]+) ([0-9:]+) ([A-Z]+): (.*)$"
[[ $log =~ $regex ]]
# Captures: date, time, level, message

Quantifiers:

  • * = Zero or more
  • + = One or more
  • ? = Zero or one
  • {n,m} = Between n and m occurrences