Skip to main content

How to Check String Matches Pattern

• 2 min read
bash pattern matching regex conditional =~ string testing

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

MethodSyntaxSpeedScopeBest For
=~ operator[[ $var =~ regex ]]FastestAnywhereVariables
glob patterns[[ $var = pattern* ]]Very fastAnywhereSimple globs
grep -Egrep -E pattern fileMediumFile linesFile content
case statementcase $var in pattern)FastPattern setsMultiple 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_REMATCH array holds captured groups (0 = whole match, 1+ = groups)
  • Don’t quote the pattern if it uses variables - =~ $pattern not =~ "$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.