6.2. Comparison & Logic#
Beyond arithmetic, you need to compare values and combine conditions using logic. These operators form the foundation of decision-making in scripts.
6.2.1. Comparison Operator Pitfalls#
6.2.1.1. ❌ Using = for Numbers#
# Wrong: This compares as strings, not numbers!
$ [ "10" = "10" ] && echo "equal" # Works but as string
$ [ "10" = "2" ] && echo "equal" # Doesn't work (string compare)
# Correct: Use -eq for numeric comparison
$ [ 10 -eq 2 ] && echo "equal" # Compares as numbers (false)
6.2.1.2. ❌ Unquoted Variables in [ ]#
# Wrong: Can break if variable has spaces
$ name="John Doe"
$ [ $name = "John Doe" ] # Error: too many arguments!
# Correct: Always quote variables in [ ]
$ [ "$name" = "John Doe" ] && echo "match"
6.2.1.3. ❌ Forgetting Escapes in [ ]#
# Wrong: < and > need escaping in [ ]
$ [ "a" < "b" ] # Redirects to file "b"!
# Correct: Escape with \
$ [ "a" \< "b" ] && echo "less"
# Or use [[ ... ]] which doesn't need escaping
$ [[ "a" < "b" ]] && echo "less"
6.2.1.4. (( … )) (Arithmetic context)#
For numeric comparisons only:
# Arithmetic operators and comparisons
$ (( 5 > 3 )) && echo "5 is greater"
# Variables don't need $ or quotes
$ a=10
$ (( a > 5 )) && echo "yes"
# Can combine arithmetic and comparison
$ (( a > 5 && a < 20 )) && echo "between 5 and 20"
# Use for loops and calculations
$ for (( i=0; i<5; i++ )); do
> echo $i
$ done
Advantages:
Clean syntax for numbers
Natural comparison operators (>, <, ==, etc.)
Good for loops and arithmetic
Disadvantages:
Numbers only (no strings)
Bash-specific
Not useful for file/string tests
6.2.1.5. [[ … ]] (Bash extended test)#
The modern, bash-specific way:
# String comparison with familiar operators
$ [[ "hello" == "hello" ]] && echo "equal"
# Number comparison (still uses -eq, -lt for safety)
$ [[ 5 -eq 5 ]] && echo "equal"
# Logic operators: && (AND), || (OR), ! (NOT)
$ [[ 5 -eq 5 && 3 -lt 10 ]] && echo "both true"
# Variables don't need quotes (safer)
$ name="John Doe"
$ [[ $name == "John Doe" ]] && echo "match" # No quotes needed!
# Supports pattern matching
$ [[ "test123" == test* ]] && echo "starts with test"
# Supports regex
$ [[ "hello123" =~ [0-9]+ ]] && echo "contains numbers"
Advantages:
More intuitive operators (&&, ||, !)
Doesn’t require quoting variables
Pattern matching and regex support
More readable
Disadvantages:
Bash-specific (not POSIX)
Won’t work in dash or sh
6.2.1.6. [ … ] (POSIX test command)#
The traditional, portable way:
# String comparison
$ [ "hello" = "hello" ] && echo "equal"
# Number comparison (needs -eq, -lt, etc.)
$ [ 5 -eq 5 ] && echo "equal"
# Logic operators: -a (AND), -o (OR), ! (NOT)
$ [ 5 -eq 5 -a 3 -lt 10 ] && echo "both true"
# Must quote variables to avoid word splitting
$ name="John Doe"
$ [ "$name" = "John Doe" ] && echo "match"
Advantages:
POSIX standard (works everywhere)
Portable to dash, sh, etc.
Disadvantages:
Need
-eq,-ltfor numbersOperators like
-a,-oare confusingQuotes required for variables
6.2.2. [ ] vs [[ ]] vs (( ))#
Three ways to test conditions in bash—choose wisely:
6.2.2.1. NOT: ! operator#
Negate a condition (flip true to false, false to true):
# ! inside [ ... ]
$ [ ! 5 -lt 3 ] && echo "5 is NOT less than 3"
5 is NOT less than 3
# ! with [ ]
$ ! [ 5 -lt 3 ] && echo "false negated = true"
false negated = true
# ! with [[ ]]
$ [[ ! "hello" == "world" ]] && echo "not equal"
not equal
# Common: check if variable is NOT empty
$ if [ ! -z "$var" ]; then
> echo "var has content"
$ fi
NOT logic:
Condition |
NOT Condition |
|---|---|
true |
false |
false |
true |
6.2.2.2. OR: -o (inside [ ]) or || (outside)#
# Inside [ ... ] use -o
$ [ 5 -lt 3 -o 10 -gt 5 ] && echo "at least one true"
at least one true
# Outside [ ... ] use ||
$ [ 5 -lt 3 ] || [ 10 -gt 5 ] && echo "at least one true"
at least one true
# In [[ ... ]] use ||
$ [[ 5 -lt 3 || 10 -gt 5 ]] && echo "at least one true"
at least one true
# Common pattern: default value
$ echo ${var:-"default"} # Use var, or "default" if var is unset
Truth table for OR:
Condition 1 |
Condition 2 |
Result |
|---|---|---|
true |
true |
true |
true |
false |
true |
false |
true |
true |
false |
false |
false |
6.2.2.3. AND: -a (inside [ ]) or && (outside)#
# Inside [ ... ] use -a
$ [ 5 -gt 3 -a 10 -gt 5 ] && echo "both true"
both true
# Outside [ ... ] use &&
$ [ 5 -gt 3 ] && [ 10 -gt 5 ] && echo "both true"
both true
# More readable: use [[ ... ]] with &&
$ [[ 5 -gt 3 && 10 -gt 5 ]] && echo "both true"
both true
# Common pattern: guard clause
$ [ -z "$var" ] && echo "var is empty" || echo "var has value"
Truth table for AND:
Condition 1 |
Condition 2 |
Result |
|---|---|---|
true |
true |
true |
true |
false |
false |
false |
true |
false |
false |
false |
false |
6.2.3. Logical Operators: AND, OR, NOT#
Combine conditions to make complex decisions:
6.2.3.1. The =, ==, !=, <, > Operators#
# = or ==: string equal
$ [ "hello" = "hello" ] && echo "equal"
equal
# !=: string not equal
$ [ "hello" != "world" ] && echo "not equal"
not equal
# <: lexicographic less than (alphabetical order)
$ [ "apple" \< "banana" ] && echo "apple comes first"
apple comes first
# >: lexicographic greater than
$ [ "zebra" \> "apple" ] && echo "zebra comes later"
zebra comes later
# Note: In [ ... ], must escape < and > as \< and \>
# In [[ ... ]], don't need escaping
$ [[ "apple" < "banana" ]] && echo "works"
works
String comparison table:
Operator |
Meaning |
Example |
Notes |
|---|---|---|---|
|
Equal |
|
Both work, |
|
Not equal |
|
True if different |
|
Less (lex) |
|
In |
|
Greater (lex) |
|
In |
6.2.4. String Comparison Operators#
These operators compare strings (text):
6.2.4.1. The -eq, -ne, -lt, -le, -gt, -ge Operators#
Use these inside [ ... ] or [[ ... ]]:
# -eq: equal
$ [ 5 -eq 5 ] && echo "equal"
equal
# -ne: not equal
$ [ 5 -ne 3 ] && echo "not equal"
not equal
# -lt: less than
$ [ 3 -lt 5 ] && echo "yes"
yes
# -le: less than or equal
$ [ 5 -le 5 ] && echo "yes"
yes
# -gt: greater than
$ [ 10 -gt 5 ] && echo "yes"
yes
# -ge: greater than or equal
$ [ 5 -ge 5 ] && echo "yes"
yes
All comparison operators:
Operator |
Meaning |
Example |
Result |
|---|---|---|---|
|
Equal |
|
true |
|
Not equal |
|
true |
|
Less than |
|
true |
|
Less or equal |
|
true |
|
Greater than |
|
true |
|
Greater or equal |
|
true |
6.2.5. Numeric Comparison Operators#
These operators compare numbers (integers) and return true (0) or false (1):