How to Check String Matches Pattern
Quick Answer: Check if String Matches Pattern
To test if a string matches a pattern, use the =~ operator in double brackets: [[ "$string" =~ pattern ]]. Returns true if the pattern matches anywhere in the string. Use ^ to anchor at start and $ to anchor at end.
Quick Comparison: Pattern Matching Methods
| Method | Syntax | Speed | Scope | Best For |
|---|---|---|---|---|
| =~ operator | [[ $var =~ regex ]] | Fastest | Anywhere | Variables |
| glob patterns | [[ $var = pattern* ]] | Very fast | Anywhere | Simple globs |
| grep -E | grep -E pattern file | Medium | File lines | File content |
| case statement | case $var in pattern) | Fast | Pattern sets | Multiple patterns |
Bottom line: Use =~ for regex matching; use glob patterns for simple matching.
Pattern Matching in Bash
Sometimes you need to check if a string matches a particular pattern - does it start with certain characters, contain numbers, match a specific format, etc. Bash provides the =~ operator for pattern matching, which is one of the most powerful conditional tools you can use.
Method 1: The =~ Operator
The =~ operator tests if a string matches a regular expression pattern. It only works inside [[ ]] conditionals:
#!/bin/bash
email="user@example.com"
# Check if string contains an @ symbol
if [[ "$email" =~ @ ]]; then
echo "Valid email format (has @)"
fi
# Check if string starts with a letter
if [[ "$email" =~ ^[a-z] ]]; then
echo "Starts with lowercase letter"
fi
Basic Pattern Examples
Here are common patterns you’ll use frequently:
#!/bin/bash
text="Hello123"
# Check for digits
if [[ "$text" =~ [0-9] ]]; then
echo "Contains numbers"
fi
# Check for uppercase
if [[ "$text" =~ [A-Z] ]]; then
echo "Contains uppercase letters"
fi
# Check for spaces
if [[ "$text" =~ \ ]]; then
echo "Contains spaces"
fi
# Check for specific word
if [[ "$text" =~ "Hello" ]]; then
echo "Contains the word Hello"
fi
Anchors: Start and End Matching
Anchors help match patterns at the beginning or end of strings:
#!/bin/bash
filename="document.txt"
# ^ means "start of string"
if [[ "$filename" =~ ^document ]]; then
echo "Filename starts with 'document'"
fi
# $ means "end of string"
if [[ "$filename" =~ \.txt$ ]]; then
echo "Filename ends with .txt"
fi
# Both together
if [[ "$filename" =~ ^[a-z]+\.txt$ ]]; then
echo "Valid filename: lowercase letters followed by .txt"
fi
Practical Example: Validation
Real-world use of pattern matching for validation:
#!/bin/bash
validate_input() {
local input="$1"
local pattern="$2"
if [[ "$input" =~ $pattern ]]; then
echo "✓ Valid"
return 0
else
echo "✗ Invalid"
return 1
fi
}
# Phone number: simple pattern (digits and hyphens)
PHONE_PATTERN='^[0-9]{3}-[0-9]{3}-[0-9]{4}$'
validate_input "123-456-7890" "$PHONE_PATTERN"
# Username: letters, numbers, underscores only
USERNAME_PATTERN='^[a-zA-Z0-9_]+$'
validate_input "john_doe123" "$USERNAME_PATTERN"
# IP address: simplified pattern
IP_PATTERN='^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
validate_input "192.168.1.1" "$IP_PATTERN"
Character Classes
Shorthand patterns for common character sets:
#!/bin/bash
text="Test123!"
# [0-9] or \d - digits
if [[ "$text" =~ [0-9] ]]; then
echo "Contains digits"
fi
# [a-zA-Z] - letters
if [[ "$text" =~ [a-zA-Z] ]]; then
echo "Contains letters"
fi
# [0-9a-zA-Z] - alphanumeric
if [[ "$text" =~ [0-9a-zA-Z] ]]; then
echo "Contains letters or digits"
fi
# [^a-z] - NOT lowercase (^ inside brackets means negation)
if [[ "$text" =~ [^a-z] ]]; then
echo "Contains non-lowercase characters"
fi
# \s - whitespace (spaces, tabs)
if [[ "$text" =~ " " ]]; then
echo "Contains spaces"
fi
Quantifiers
Control how many times a pattern should match:
#!/bin/bash
# ? - zero or one
if [[ "color" =~ colou?r ]]; then
echo "Matches 'color' or 'colour'"
fi
# * - zero or more
if [[ "aaa" =~ a* ]]; then
echo "Matches zero or more 'a' characters"
fi
# + - one or more
if [[ "aaa" =~ a+ ]]; then
echo "Matches one or more 'a' characters"
fi
# {n} - exactly n times
if [[ "abc123" =~ [0-9]{3} ]]; then
echo "Contains exactly 3 digits"
fi
# {n,m} - between n and m times
if [[ "abc12" =~ [0-9]{1,3} ]]; then
echo "Contains 1 to 3 digits"
fi
Practical Example: Log File Analysis
#!/bin/bash
# Sample log entry
LOG_ENTRY="2026-02-21 14:30:45 ERROR Database connection failed"
# Extract and validate timestamp
if [[ "$LOG_ENTRY" =~ ^([0-9]{4})-([0-9]{2})-([0-9]{2})\ ([0-9]{2}):([0-9]{2}):([0-9]{2}) ]]; then
echo "Valid timestamp: ${BASH_REMATCH[0]}"
fi
# Check for error level
ERROR_LEVELS="ERROR|WARN|INFO|DEBUG"
if [[ "$LOG_ENTRY" =~ ($ERROR_LEVELS) ]]; then
level="${BASH_REMATCH[1]}"
echo "Log level: $level"
fi
Using Captured Groups (BASH_REMATCH)
When you use parentheses in your pattern, Bash captures the matched groups:
#!/bin/bash
# Extract name and domain from email
email="john@example.com"
if [[ "$email" =~ ([a-z]+)@([a-z]+\.[a-z]+) ]]; then
username="${BASH_REMATCH[1]}"
domain="${BASH_REMATCH[2]}"
echo "Username: $username"
echo "Domain: $domain"
fi
Important Notes
=~only works inside[[ ]], not with single[ ]- Patterns use Extended Regular Expressions (ERE)
BASH_REMATCHarray holds captured groups (0 = whole match, 1+ = groups)- Don’t quote the pattern if it uses variables -
=~ $patternnot=~ "$pattern" - Backslash escaping is needed for special characters:
\.for literal dot,\$for literal dollar
Common Patterns Reference
# Email-like pattern (simple, not RFC compliant)
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
# URL
^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
# IP address (simple)
^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$
# Date (YYYY-MM-DD)
^[0-9]{4}-[0-9]{2}-[0-9]{2}$
# Time (HH:MM:SS)
^[0-9]{2}:[0-9]{2}:[0-9]{2}$
# Hex color
^#[0-9a-fA-F]{6}$
# Numbers only
^[0-9]+$
# Alphanumeric only
^[a-zA-Z0-9]+$
Summary
Pattern matching with =~ is essential for validation and text processing. Master this operator and you’ll be able to validate input, extract data, and handle complex conditional logic efficiently.