Przejdź do treści

⚖️ Extended Conditionals and Tests

Conditional logic forms the backbone of every non-trivial script. This section covers both basic and advanced testing mechanisms.

🧭 Test Command Fundamentals

The test command (or its alias [) evaluates conditions and returns exit code:

1
2
3
if [ "$USER" = "root" ]; then
    echo "Running as root"
fi

Key points: - Spaces around [ and ] are mandatory - Use = for string comparison (not == in POSIX) - Quote variables to prevent word splitting


🧪 File Tests

Operator Meaning Example
-e FILE Exists [ -e /etc/passwd ]
-f FILE Regular file [ -f script.sh ]
-d DIR Directory [ -d /home ]
-r FILE Readable [ -r config.yml ]
-w FILE Writable [ -w /tmp ]
-x FILE Executable [ -x /usr/bin/grep ]
-s FILE Size > 0 [ -s data.txt ]
-L FILE Symbolic link [ -L /usr/bin/python ]
-nt F1 F2 F1 newer than F2 [ file1 -nt file2 ]
-ot F1 F2 F1 older than F2 [ file1 -ot file2 ]

🧠 String Comparisons

Operator Meaning POSIX?
= Equal
!= Not equal
-z STR Empty string
-n STR Non-empty string

Examples:

1
2
3
4
5
6
7
8
if [ -z "$INPUT" ]; then
    echo "No input provided"
    exit 1
fi

if [ "$ENV" = "production" ]; then
    echo "Running in production mode"
fi

⚠️ Avoid == in POSIX scripts — use = instead.


🧪 Numeric Comparisons

Operator Meaning Example
-eq Equal [ $count -eq 0 ]
-ne Not equal [ $count -ne 0 ]
-lt Less than [ $age -lt 18 ]
-le Less or equal [ $retries -le 3 ]
-gt Greater than [ $size -gt 100 ]
-ge Greater or equal [ $score -ge 90 ]

Important: These operators work only with integers.

1
2
3
4
count=5
if [ $count -gt 0 ] && [ $count -lt 10 ]; then
    echo "Count is between 1 and 9"
fi

🧠 Logical Operators

Combine multiple conditions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# AND (both must be true)
if [ -f config.yml ] && [ -r config.yml ]; then
    echo "Config exists and is readable"
fi

# OR (at least one must be true)
if [ "$USER" = "root" ] || [ "$USER" = "admin" ]; then
    echo "Privileged user"
fi

# NOT (invert condition)
if [ ! -d /tmp/cache ]; then
    mkdir -p /tmp/cache
fi

Group with parentheses (escaped in POSIX):

1
2
3
if [ \( -f file1 -o -f file2 \) -a -r file1 ]; then
    echo "At least one file exists and file1 is readable"
fi

🧪 Bash/Zsh Extended Tests

Double brackets [[ ]] offer more features:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Pattern matching
if [[ "$hostname" == *.example.com ]]; then
    echo "This is an example.com host"
fi

# Regex matching
if [[ "$email" =~ ^[a-z]+@[a-z]+\.[a-z]+$ ]]; then
    echo "Valid email format"
fi

# String comparison with ==
if [[ "$lang" == "en" || "$lang" == "pl" ]]; then
    echo "Supported language"
fi

Advantages of [[ ]]: - No word splitting on unquoted variables - Supports && and || inside - Supports regex with =~ - Supports pattern matching with ==

⚠️ Not POSIX — avoid in portable scripts.


🧠 Case Statements

For multiple string comparisons, case is cleaner than nested if:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
case "$1" in
    start)
        echo "Starting service..."
        ;;
    stop)
        echo "Stopping service..."
        ;;
    restart)
        echo "Restarting service..."
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

Pattern matching in case:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
case "$filename" in
    *.txt|*.log)
        echo "Text file"
        ;;
    *.jpg|*.png|*.gif)
        echo "Image file"
        ;;
    *)
        echo "Unknown type"
        ;;
esac

🧪 Arithmetic Conditions

Bash supports arithmetic evaluation:

1
2
3
4
5
6
7
if (( count > 0 )); then
    echo "Positive count"
fi

if (( (a > b) && (c < d) )); then
    echo "Complex condition met"
fi

Or with let:

1
2
3
4
let "result = 5 + 3"
if [ $result -eq 8 ]; then
    echo "Math works"
fi

🧾 Portability Comparison

Feature POSIX [ ] Bash [[ ]]
String equality = = or ==
Pattern matching
Regex matching
Logical AND/OR -a / -o && / ||
Word splitting ⚠️ Quote! ✅ Safe
Arithmetic (( ))

🧾 Summary

  • Use [ ] for portable scripts — always quote variables.
  • Use [[ ]] for Bash/Zsh-specific features.
  • Prefer case over nested if for multiple branches.
  • Numeric tests use -eq, -lt, etc. — not ==, <, etc.
  • Combine conditions with &&, ||, ! for complex logic.

👉 Continue to: Loops and Iteration