How to Compare Strings in Bash
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
| Method | Best For | Operator | Complexity |
|---|---|---|---|
| Equality check | Same/different strings | = or != | Very simple |
| Lexicographic | Alphabetical order | < or > | Simple |
| Pattern matching | Wildcard matching | =~ or * | Moderate |
| Case-insensitive | Ignoring case | ${var,,} + = | Moderate |
| Numeric (if numbers) | Number comparison | -eq, -lt, -gt | Simple |
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,-gtinstead) - 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.