Skip to main content

How to Compare Strings in Bash

• 4 min read
bash string comparison conditional equality

Quick Answer: Compare Strings in Bash

To compare strings in Bash, use the = operator for equality or != for inequality: if [ "$str1" = "$str2" ]. For lexicographic (alphabetical) comparison, use < or >. Always quote variables to prevent word splitting errors.

Quick Comparison: String Comparison Methods

MethodBest ForOperatorComplexity
Equality checkSame/different strings= or !=Very simple
LexicographicAlphabetical order< or >Simple
Pattern matchingWildcard matching=~ or *Moderate
Case-insensitiveIgnoring case${var,,} + =Moderate
Numeric (if numbers)Number comparison-eq, -lt, -gtSimple

Bottom line: Use = for equality, </> for ordering, and =~ for pattern matching.


Method 1: String Equality (The Essential Test)

Check if two strings are exactly the same using the = operator. This is the most common string comparison you’ll do. Always quote your variables to prevent word-splitting issues.

Basic Equality Check

Here’s the fundamental pattern:

str1="hello"
str2="hello"

if [ "$str1" = "$str2" ]; then
  echo "Strings are equal"
fi

The = operator returns true if the strings are identical. Notice the quotes around $str1 and $str2—they’re essential to prevent errors if the variables contain spaces or special characters.

Checking Against a Literal String

You can compare a variable against a fixed string:

username="$1"

if [ "$username" = "admin" ]; then
  echo "Admin user detected"
fi

This is common when checking for specific values or keywords.

When to Use Equality Check

Use = when:

  • You need to check if two strings are identical
  • Validating user input against expected values
  • Testing if a variable matches a specific string
  • You want POSIX-compatible code (works everywhere)

Skip it when:

  • You need to check order (use < or >)
  • You want pattern matching with wildcards (use =~)
  • You need case-insensitive comparison (use ${var,,})

Method 2: String Inequality (The Opposite Check)

Use the != operator to check if strings are different. This is useful when you want to verify that two things don’t match, such as confirming passwords.

Basic Inequality Check

str1="hello"
str2="world"

if [ "$str1" != "$str2" ]; then
  echo "Strings are different"
fi

The != operator is the opposite of =—it’s true when strings don’t match.

Real-World Inequality Example

password="secret123"
confirm="secret123"

if [ "$password" != "$confirm" ]; then
  echo "Passwords do not match"
  exit 1
fi

echo "Passwords match"

This is essential for user input validation, especially when confirming passwords or verifying matching fields.

When to Use Inequality

Use != when:

  • Validating that two inputs match (like password confirmation)
  • Checking that a value is not a specific keyword
  • Testing that variables have different values
  • Creating guard conditions

Method 3: Lexicographic Comparison (For Ordering)

Use < and > to compare strings alphabetically. Lexicographic means “dictionary order”—comparing letter by letter from left to right using ASCII values.

Check if String Comes Before Another

str1="apple"
str2="banana"

if [ "$str1" < "$str2" ]; then
  echo "apple comes before banana alphabetically"
fi

The < operator compares strings in alphabetical order. “apple” comes before “banana” in the dictionary, so this evaluates to true.

Check if String Comes After Another

str1="zebra"
str2="apple"

if [ "$str1" > "$str2" ]; then
  echo "zebra comes after apple alphabetically"
fi

The > operator is the opposite—true when the first string comes after the second alphabetically.

Important: Escape in [ ] Syntax

When using < or > with single brackets, you need to escape them with backslash to prevent shell redirection:

# CORRECT: Escape the operators
if [ "$str1" \< "$str2" ]; then
  echo "less than"
fi

# OR use [[ ]] where escaping isn't needed
if [[ "$str1" < "$str2" ]]; then
  echo "less than"
fi

When to Use Lexicographic Comparison

Use < or > when:

  • Sorting strings alphabetically
  • Checking version numbers (with caution—“10” comes before “2” alphabetically)
  • Validating string ranges
  • Implementing custom sorting logic

Skip it when:

  • Comparing numbers (use -lt, -gt instead)
  • You need case-insensitive comparison

Method 4: Using [[ ]] (Modern Bash)

The [[ ]] syntax is Bash-specific and more powerful than [ ]. It’s safer for string comparison and offers better handling of edge cases.

Basic Comparison with [[]]

str1="hello"
str2="hello"

if [[ $str1 == $str2 ]]; then
  echo "Strings are equal"
fi

Notice you don’t need to quote variables in [[ ]]—it’s more forgiving. You can use == instead of = (they’re equivalent in Bash).

Why [[ ]] is Better

# Using [ ] requires quotes to avoid errors
var="hello world"
[ $var = "hello world" ]  # ERROR: too many arguments

# Using [[ ]] works without quotes
[[ $var == "hello world" ]]  # Works correctly

With [[ ]], you can safely use unquoted variables without fear of word splitting.

When to Use [[]]

Use [[ ]] when:

  • Writing modern Bash scripts (not for POSIX sh)
  • You want cleaner, safer comparison syntax
  • You’re using pattern matching
  • You need regex support

Use [ ] when:

  • You need POSIX compatibility (shell scripts must work in sh)
  • Writing portable shell scripts
  • The script needs to run on very old systems

Method 5: Pattern Matching (For Wildcards)

Use =~ or == with wildcards to match patterns instead of exact strings. This is useful for checking file types or validating formats.

Simple Wildcard Matching

filename="script.sh"

if [[ $filename == *.sh ]]; then
  echo "Is a shell script"
fi

The * wildcard matches any characters. This checks if the filename ends in .sh.

Pattern Matching with Regex

email="john@example.com"

if [[ $email =~ ^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]+$ ]]; then
  echo "Valid email format"
fi

The =~ operator uses regular expressions for powerful pattern matching. This is much more sophisticated than simple wildcards.

When to Use Pattern Matching

Use == with wildcards when:

  • Checking file extensions
  • Simple wildcard matching needed
  • Pattern is easy to express with * and ?

Use =~ with regex when:

  • Validating email addresses or phone numbers
  • Matching complex patterns
  • Need precise format validation
  • Capturing parts of the match (regex groups)

Method 6: Case-Insensitive Comparison

Convert strings to lowercase (or uppercase) for case-insensitive comparison. This is useful when you need to ignore capitalization differences.

Convert to Lowercase and Compare

str1="Hello"
str2="hello"

if [ "${str1,,}" = "${str2,,}" ]; then
  echo "Strings are equal (ignoring case)"
fi

The ${var,,} syntax converts to lowercase. This is a Bash 4+ feature.

Alternative for Older Bash

For compatibility with Bash 3, use tr:

str1="Hello"
str2="hello"

if [ "$(echo "$str1" | tr '[:upper:]' '[:lower:]')" = "$(echo "$str2" | tr '[:upper:]' '[:lower:]')" ]; then
  echo "Strings are equal (ignoring case)"
fi

Less elegant but works on older systems.

When to Use Case-Insensitive Comparison

Use when:

  • User input might have mixed capitalization
  • Comparing keywords that should ignore case
  • File matching on case-sensitive systems
  • Username validation

Practical Examples

Example 1: Validate User Input

#!/bin/bash

read -p "Enter command (yes/no): " response

if [ "$response" = "yes" ]; then
  echo "User confirmed"
elif [ "$response" = "no" ]; then
  echo "User declined"
else
  echo "Invalid response"
fi

Simple string comparison for user validation.

Example 2: Check Current User

#!/bin/bash

user=$(whoami)

if [ "$user" = "root" ]; then
  echo "Running with root privileges"
elif [ "$user" = "admin" ]; then
  echo "Running as admin"
else
  echo "Running as regular user: $user"
fi

Check who’s running the script using string comparison.

Example 3: Sort Filenames

#!/bin/bash

file1="$1"
file2="$2"

if [[ "$file1" < "$file2" ]]; then
  echo "$file1 comes first"
else
  echo "$file2 comes first (or equal)"
fi

Use lexicographic comparison to order filenames.

Example 4: File Type Detection

#!/bin/bash

filename="$1"

if [[ $filename == *.txt ]]; then
  echo "Text file"
elif [[ $filename == *.sh ]]; then
  echo "Shell script"
elif [[ $filename == *.jpg || $filename == *.png ]]; then
  echo "Image file"
else
  echo "Unknown type"
fi

Use wildcards to detect file types.

Example 5: Email Validation

#!/bin/bash

email="$1"

if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
  echo "Valid email format"
else
  echo "Invalid email format"
fi

Use regex for proper email validation.

Example 6: Case-Insensitive Username Check

#!/bin/bash

username="$1"
admin_user="admin"

if [ "${username,,}" = "${admin_user,,}" ]; then
  echo "Admin account detected"
else
  echo "Regular user account"
fi

Compare usernames while ignoring case differences.

Example 7: Multi-String Comparison

#!/bin/bash

status="$1"

if [ "$status" = "running" ] || [ "$status" = "active" ]; then
  echo "Service is up"
elif [ "$status" = "stopped" ] || [ "$status" = "inactive" ]; then
  echo "Service is down"
else
  echo "Status unknown: $status"
fi

Compare against multiple possible values.

Quick Reference

# Equality
[ "$str1" = "$str2" ]
[[ $str1 == $str2 ]]

# Inequality
[ "$str1" != "$str2" ]

# Lexicographic comparison
[ "$str1" \< "$str2" ]  # less than (escape with \)
[[ "$str1" < "$str2" ]] # less than (no escape needed)

# Greater than
[ "$str1" \> "$str2" ]
[[ "$str1" > "$str2" ]]

# Pattern matching
[[ $filename == *.txt ]]

# Regex matching
[[ $text =~ ^[0-9]+$ ]]

# Case-insensitive
[ "${str1,,}" = "${str2,,}" ]

# Empty string check
[ -z "$str" ]      # true if empty
[ -n "$str" ]      # true if not empty

Summary

For string comparison, start with the = operator for equality checks using [ ] for portability, or [[ ]] for modern Bash scripts. Use < and > for alphabetical ordering, pattern matching (== with wildcards) for file type detection, and =~ with regex for format validation. Always quote your variables in [ ] to avoid shell splitting issues. Choose case-insensitive comparison only when capitalization doesn’t matter for your use case.