Test Operators
Test operators are the conditions you use inside [ ] and [[ ]]. Mastering these operators is essential for writing effective conditionals.
String Comparison Operators
| Operator | Description | Example |
|---|---|---|
= | Equal | [ "$a" = "$b" ] |
== | Equal (same as =) | [ "$a" == "$b" ] |
!= | Not equal | [ "$a" != "$b" ] |
-z | String is empty | [ -z "$a" ] |
-n | String is not empty | [ -n "$a" ] |
< | Less than (ASCII) | [[ "$a" < "$b" ]] |
> | Greater than (ASCII) | [[ "$a" > "$b" ]] |
#!/bin/bash
NAME="Alice"
if [ "$NAME" = "Alice" ]; then
echo "Hello Alice!"
fi
if [ -n "$NAME" ]; then
echo "Name is set"
fi
Important: = vs ==
In [ ], both = and == work, but = is POSIX standard:
# Both work in bash
[ "$a" = "$b" ] # POSIX compliant
[ "$a" == "$b" ] # Bash extension
# In [[ ]], == enables pattern matching
[[ "$a" == pattern* ]]
Numeric Comparison Operators
| Operator | Description | Example |
|---|---|---|
-eq | Equal | [ "$a" -eq "$b" ] |
-ne | Not equal | [ "$a" -ne "$b" ] |
-lt | Less than | [ "$a" -lt "$b" ] |
-le | Less than or equal | [ "$a" -le "$b" ] |
-gt | Greater than | [ "$a" -gt "$b" ] |
-ge | Greater than or equal | [ "$a" -ge "$b" ] |
#!/bin/bash
AGE=25
if [ "$AGE" -ge 18 ]; then
echo "Adult"
fi
if [ "$AGE" -lt 65 ]; then
echo "Working age"
fi
Exercise: Numeric Comparison
Use numeric operators:
File Test Operators
| Operator | Description |
|---|---|
-e FILE | File exists (any type) |
-f FILE | Regular file exists |
-d FILE | Directory exists |
-r FILE | File is readable |
-w FILE | File is writable |
-x FILE | File is executable |
-s FILE | File exists and is not empty |
-L FILE | File is a symbolic link |
-p FILE | File is a named pipe |
-S FILE | File is a socket |
#!/bin/bash
FILE="/etc/hosts"
if [ -f "$FILE" ]; then
echo "File exists"
fi
if [ -r "$FILE" ]; then
echo "File is readable"
fi
if [ -s "$FILE" ]; then
echo "File is not empty"
fi
File Comparison Operators
| Operator | Description |
|---|---|
FILE1 -nt FILE2 | FILE1 is newer than FILE2 |
FILE1 -ot FILE2 | FILE1 is older than FILE2 |
FILE1 -ef FILE2 | Same file (same device and inode) |
#!/bin/bash
if [ "source.c" -nt "source.o" ]; then
echo "Source is newer, need to recompile"
fi
Exercise: Check Directory
Test if a path is a directory:
Logical Operators
Inside [ ] (traditional)
| Operator | Description |
|---|---|
! | NOT |
-a | AND |
-o | OR |
# NOT
if [ ! -f "$FILE" ]; then
echo "Not a file"
fi
# AND (avoid using -a)
if [ "$A" -gt 5 -a "$B" -lt 10 ]; then
echo "Both true"
fi
# Better: use separate brackets
if [ "$A" -gt 5 ] && [ "$B" -lt 10 ]; then
echo "Both true"
fi
Inside [[ ]] (bash)
| Operator | Description |
|---|---|
! | NOT |
&& | AND |
|| | OR |
if [[ $A -gt 5 && $B -lt 10 ]]; then
echo "Both true"
fi
if [[ $A -eq 1 || $A -eq 2 ]]; then
echo "A is 1 or 2"
fi
Pattern Matching in [[ ]]
Use == with glob patterns:
#!/bin/bash
FILE="document.txt"
if [[ $FILE == *.txt ]]; then
echo "Text file"
fi
if [[ $FILE == doc* ]]; then
echo "Starts with 'doc'"
fi
if [[ $FILE == ????.??? ]]; then
echo "Matches pattern: 4 chars, dot, 3 chars"
fi
Regex Matching in [[ ]]
Use =~ for regular expressions:
#!/bin/bash
EMAIL="user@example.com"
if [[ $EMAIL =~ ^[a-z]+@[a-z]+\.[a-z]+$ ]]; then
echo "Valid email"
fi
# Access captured groups with BASH_REMATCH
if [[ $EMAIL =~ ^([a-z]+)@([a-z]+\.[a-z]+)$ ]]; then
echo "User: ${BASH_REMATCH[1]}"
echo "Domain: ${BASH_REMATCH[2]}"
fi
Exercise: Pattern Match
Use pattern matching:
The test Command
[ ] is actually an alias for test:
# These are equivalent
if [ -f "$FILE" ]; then
if test -f "$FILE"; then
# Check test's exit code directly
test -f "$FILE"
echo $? # 0 if file exists, 1 otherwise
Compound Expressions
Group conditions with parentheses:
# In [[ ]], parentheses work naturally
if [[ ( $A -eq 1 || $A -eq 2 ) && $B -gt 5 ]]; then
echo "Complex condition met"
fi
# In [ ], escape parentheses
if [ \( "$A" -eq 1 -o "$A" -eq 2 \) -a "$B" -gt 5 ]; then
echo "Complex condition met"
fi
Common Operator Mistakes
# WRONG: Using == outside quotes in [ ]
[ $VAR == "value" ] # Can fail if VAR is empty
# CORRECT: Always quote
[ "$VAR" == "value" ]
# WRONG: Spaces missing
[$VAR -eq 5] # Error!
# CORRECT: Spaces required
[ "$VAR" -eq 5 ]
# WRONG: Using = for numbers
[ "$A" = "$B" ] # String comparison!
# CORRECT: Use -eq for numbers
[ "$A" -eq "$B" ]
# WRONG: Using < > in [ ] without escaping
[ $A < $B ] # Tries to redirect!
# CORRECT: Use -lt or escape
[ "$A" -lt "$B" ]
[[ $A < $B ]]
Quick Reference
# String tests
[ -z "$STR" ] # Empty
[ -n "$STR" ] # Not empty
[ "$A" = "$B" ] # Equal
[ "$A" != "$B" ] # Not equal
# Numeric tests
[ "$A" -eq "$B" ] # Equal
[ "$A" -ne "$B" ] # Not equal
[ "$A" -lt "$B" ] # Less than
[ "$A" -gt "$B" ] # Greater than
# File tests
[ -e "$F" ] # Exists
[ -f "$F" ] # Is file
[ -d "$F" ] # Is directory
[ -r "$F" ] # Readable
[ -w "$F" ] # Writable
[ -x "$F" ] # Executable
# Pattern matching (in [[ ]])
[[ $S == pattern* ]] # Glob pattern
[[ $S =~ regex ]] # Regex match
Key Takeaways
- Use
-eq,-ne,-lt,-gtfor numeric comparisons - Use
=,!=,-z,-nfor string comparisons - Use
-f,-d,-e,-r,-w,-xfor file tests - Prefer
[[ ]]over[ ]in bash scripts [[ ]]allows pattern matching with==and regex with=~- Always quote variables in test expressions
- Remember the space requirements:
[ "$VAR" -eq 5 ]

