Skip to main content

How to Match Regex in Bash

• 2 min read
bash regex pattern matching regular expression =~ operator

Quick Answer: Match Regex in Bash

To match a regex pattern, use the =~ operator in Bash: [[ "$string" =~ pattern ]]. This returns true if the pattern matches anywhere in the string. Anchor with ^ for start and $ for end. The =~ operator is Bash’s native regex matching method.

Quick Comparison: Regex Matching Methods

MethodSyntaxSpeedBest ForComplexity
=~ operator[[ $var =~ regex ]]FastestBash conditionalsSimple
grep -Egrep -E pattern fileMediumFile contentSimple
sed /pattern/sed -n '/pattern/p'MediumLine filteringModerate
awk /pattern/awk '/pattern/'FastStructured dataModerate

Bottom line: Use =~ for strings; use grep for files and pipes.


Use regular expressions to match patterns in bash strings. Learn using the =~ operator, test functions, and regex syntax.

Method 1: Basic Regex Matching (The Standard)

Use the =~ operator to match patterns against strings:

# Test if string matches pattern
if [[ $string =~ pattern ]]; then
  echo "Match!"
fi

# Example
if [[ "hello" =~ ^h ]]; then
  echo "Starts with h"
fi

When to Use Basic Pattern Matching

Use this when:

  • You’re checking if a string contains a pattern
  • You need simple pattern matching in conditionals
  • You want the fastest Bash-native solution
  • You’re validating input formats

Simple Pattern Examples

# Check if string contains substring
if [[ $text =~ "word" ]]; then
  echo "Contains word"
fi

# Check if starts with
if [[ $text =~ ^start ]]; then
  echo "Starts with 'start'"
fi

# Check if ends with
if [[ $text =~ end$ ]]; then
  echo "Ends with 'end'"
fi

# Check if only digits
if [[ $text =~ ^[0-9]+$ ]]; then
  echo "All digits"
fi

Practical Example: Email Validation

#!/bin/bash

# File: validate_email.sh

validate_email() {
  local email="$1"

  # Simple email pattern
  if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
    return 0
  else
    return 1
  fi
}

# Usage
emails=("user@example.com" "invalid@" "test@domain.co.uk" "no-at-sign.com")

for email in "${emails[@]}"; do
  if validate_email "$email"; then
    echo "✓ Valid: $email"
  else
    echo "✗ Invalid: $email"
  fi
done

Output:

✓ Valid: user@example.com
✗ Invalid: invalid@
✓ Valid: test@domain.co.uk
✗ Invalid: no-at-sign.com

Capture Groups

#!/bin/bash

# Use capture groups with BASH_REMATCH

text="User: John, Age: 30"

if [[ $text =~ User:\ ([a-zA-Z]+),\ Age:\ ([0-9]+) ]]; then
  name="${BASH_REMATCH[1]}"
  age="${BASH_REMATCH[2]}"
  echo "Name: $name"
  echo "Age: $age"
fi

Output:

Name: John
Age: 30

Practical Example: Log Parser

#!/bin/bash

# File: parse_log_line.sh

log_line="2026-02-21 14:30:45 ERROR Connection refused from 192.168.1.1"

# Parse log format
if [[ $log_line =~ ^([0-9-]+)\ ([0-9:]+)\ ([A-Z]+)\ (.*)\ from\ ([0-9.]+)$ ]]; then
  date="${BASH_REMATCH[1]}"
  time="${BASH_REMATCH[2]}"
  level="${BASH_REMATCH[3]}"
  message="${BASH_REMATCH[4]}"
  ip="${BASH_REMATCH[5]}"

  echo "Date: $date"
  echo "Time: $time"
  echo "Level: $level"
  echo "Message: $message"
  echo "IP: $ip"
fi

URL Validation

#!/bin/bash

# Validate URL format

url="$1"

if [[ $url =~ ^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} ]]; then
  echo "✓ Valid URL: $url"
else
  echo "✗ Invalid URL: $url"
fi

IP Address Matching

#!/bin/bash

# Validate IP address (IPv4)

validate_ip() {
  local ip="$1"

  # Pattern for IPv4: 0-255.0-255.0-255.0-255
  if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
    # Check ranges (simple check, not perfect)
    return 0
  else
    return 1
  fi
}

if validate_ip "192.168.1.1"; then
  echo "Valid IP"
fi

Case-Insensitive Matching

# Use shopt nocasematch
shopt -s nocasematch

if [[ "HELLO" =~ hello ]]; then
  echo "Match (case-insensitive)"
fi

shopt -u nocasematch  # Turn off

NOT Matching

# Check if does NOT match
if [[ ! $text =~ pattern ]]; then
  echo "Does not match"
fi

# Example
if [[ ! "hello" =~ ^[0-9] ]]; then
  echo "Doesn't start with digit"
fi

Multiple Patterns

#!/bin/bash

# Check multiple patterns

text="$1"

if [[ $text =~ ^(error|warning|info) ]]; then
  level="${BASH_REMATCH[1]}"
  echo "Log level: $level"
fi

Password Strength Check

#!/bin/bash

# Validate password strength

validate_password() {
  local pass="$1"

  # At least 8 chars, contains uppercase, lowercase, digit, special
  if [[ ${#pass} -ge 8 ]] && \
     [[ $pass =~ [A-Z] ]] && \
     [[ $pass =~ [a-z] ]] && \
     [[ $pass =~ [0-9] ]] && \
     [[ $pass =~ [^a-zA-Z0-9] ]]; then
    return 0
  else
    return 1
  fi
}

if validate_password "MyPass123!"; then
  echo "✓ Strong password"
else
  echo "✗ Weak password"
fi

Extract Numbers from String

#!/bin/bash

text="Price: $19.99 Quantity: 5 Discount: 10%"

if [[ $text =~ \$([0-9.]+) ]]; then
  price="${BASH_REMATCH[1]}"
  echo "Price: $price"
fi

if [[ $text =~ Quantity:\ ([0-9]+) ]]; then
  quantity="${BASH_REMATCH[1]}"
  echo "Quantity: $quantity"
fi

Output:

Price: 19.99
Quantity: 5

Practical Example: Filename Pattern

#!/bin/bash

# Check if filename matches pattern

filename="report_2026_02_21.pdf"

if [[ $filename =~ ^([a-z_]+)_([0-9]{4})_([0-9]{2})_([0-9]{2})\.[a-z]+$ ]]; then
  name="${BASH_REMATCH[1]}"
  year="${BASH_REMATCH[2]}"
  month="${BASH_REMATCH[3]}"
  day="${BASH_REMATCH[4]}"

  echo "Name: $name"
  echo "Date: $year-$month-$day"
fi

Output:

Name: report
Date: 2026-02-21

Common Regex Patterns

# Digits only
[0-9]+

# Letters only
[a-zA-Z]+

# Alphanumeric
[a-zA-Z0-9]+

# Email-like
[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+

# IP address
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}

# URL
https?://[a-zA-Z0-9.-]+

# Phone number
[0-9]{3}-[0-9]{3}-[0-9]{4}

# Hex color
#[0-9a-fA-F]{6}

# Start/end
^ start, $ end

Error Checking

#!/bin/bash

text="$1"

if [[ -z $text ]]; then
  echo "ERROR: No text provided"
  exit 1
fi

if [[ $text =~ ^[a-z]+$ ]]; then
  echo "Matches pattern: lowercase letters only"
else
  echo "Does not match pattern"
fi

Common Mistakes

  1. Missing [[ ]] double brackets - regex only works with [[]], not []
  2. Not escaping special characters - use \ for ., *, etc.
  3. Forgetting space escaping - \ for literal space
  4. BASH_REMATCH indexing - [0] is full match, [1] is first group
  5. Not quoting variables - can break pattern matching

Performance Tips

  • Test patterns on sample data first
  • Use anchors ^ and $ for exact matches
  • Avoid complex nested patterns
  • Cache pattern matches in variables

Key Points

  • Use [[ $var =~ pattern ]] for matching
  • Use BASH_REMATCH for capture groups
  • Escape special regex characters
  • Test patterns thoroughly
  • Remember double brackets required

Summary

Regular expression matching in bash uses the =~ operator with extended regex. Always use double brackets, handle capture groups properly, and test patterns thoroughly before using in production.