7.1. if/elif/else and case Statements#

Two powerful ways to make decisions in bash: sequential conditions and pattern matching.

7.1.1. Common Pitfalls#

7.1.1.1. ❌ Missing Quotes in Conditions#

# Wrong: unquoted $var can break
user=$1
if [ $user = "admin" ]; then  # Fails if user empty!
  echo "admin"
fi

# Correct: always quote variables
if [ "$user" = "admin" ]; then
  echo "admin"
fi

7.1.1.2. ❌ Missing Semicolon Before fi/done#

# Wrong: no ; before fi
if [ -f "$file" ]
then
  echo "found"
fi  # Error!

# Correct: semicolon (or newline) required
if [ -f "$file" ]; then
  echo "found"
fi

7.1.1.3. ❌ Not Using ;; in case#

# Wrong: missing ;; causes fall-through
case $var in
  a) echo "a" 
  b) echo "b"   # This always runs after a!
esac

# Correct: each case ends with ;;
case $var in
  a) echo "a" ;;
  b) echo "b" ;;
esac

7.1.2. Comparison: if/elif vs case#

7.1.2.1. When to use if/elif#

# Good for: Complex conditions, ranges, comparisons
if [ $count -gt 100 ]; then
  echo "Too many"
elif [ $count -gt 50 ]; then
  echo "Many"
else
  echo "Few"
fi

Best for:

  • Range checks (>, <, >=, <=)

  • Combining multiple conditions (&&, ||, !)

  • File/string tests (-f, -z, etc.)

7.1.2.2. When to use case#

# Good for: Matching one variable against patterns
case $option in
  -v|--verbose) verbose=1 ;;
  -q|--quiet) quiet=1 ;;
  -h|--help) show_help ;;
esac

Best for:

  • Single variable, multiple patterns

  • Command-line options/arguments

  • File extensions or types

  • Cleaner, more readable code

7.1.2.3. Combining Conditions with &&, ||, and ()#

Nest conditions for complex logic:

#!/bin/bash
file=$1
action=$2

if [ -f "$file" ] && [ -r "$file" ]; then
  case $action in
    read)
      cat "$file"
      ;;
    count)
      wc -l "$file"
      ;;
    *)
      echo "Unknown action"
      ;;
  esac
elif [ ! -e "$file" ]; then
  echo "File doesn't exist"
elif [ ! -r "$file" ]; then
  echo "File not readable"
fi

7.1.2.4. Pattern Matching with Wildcards#

case supports glob patterns:

#!/bin/bash
filename=$1

case $filename in
  *.txt)
    echo "Text file"
    ;;
  *.log)
    echo "Log file"
    ;;
  *.sh)
    echo "Shell script"
    ;;
  *.jpg|*.png|*.gif)
    echo "Image file"
    ;;
  *)
    echo "Unknown file type"
    ;;
esac

Glob pattern examples:

  • *.txt - ends with .txt

  • file* - starts with “file”

  • test[0-9] - test followed by digit

  • ?(pattern) - optional pattern (bash extglob)

  • +(pattern) - one or more patterns

  • @(a|b|c) - exactly one of a, b, or c

7.1.2.5. Simple case Example#

#!/bin/bash
command=$1

case $command in
  start)
    echo "Starting service..."
    ;;
  stop)
    echo "Stopping service..."
    ;;
  restart)
    echo "Restarting service..."
    ;;
  status)
    echo "Service is running"
    ;;
  *)
    echo "Unknown command: $command"
    echo "Use: start, stop, restart, or status"
    exit 1
    ;;
esac

Usage:

$ bash service.sh start
Starting service...

$ bash service.sh unknown
Unknown command: unknown
Use: start, stop, restart, or status

7.1.3. case: Pattern Matching#

More elegant than if/elif for checking one variable against multiple patterns:

case $variable in
  pattern1)
    # code if variable matches pattern1
    ;;
  pattern2)
    # code if variable matches pattern2
    ;;
  pattern3|pattern4)
    # code if variable matches pattern3 OR pattern4
    ;;
  *)
    # default case (optional)
    ;;
esac

Key points:

  • Each pattern ends with )

  • Code block ends with ;;

  • | means OR (alternative patterns)

  • * is the default (catch-all)

7.1.3.1. if/elif/else#

Test multiple conditions in sequence:

if [ condition1 ]; then
  # runs if condition1 is true
elif [ condition2 ]; then
  # runs if condition1 false AND condition2 true
elif [ condition3 ]; then
  # runs if conditions 1,2 false AND condition3 true
else
  # runs if all conditions false
fi

Real example: Grade calculator

#!/bin/bash
score=$1

if [ $score -ge 90 ]; then
  echo "Grade: A"
elif [ $score -ge 80 ]; then
  echo "Grade: B"
elif [ $score -ge 70 ]; then
  echo "Grade: C"
elif [ $score -ge 60 ]; then
  echo "Grade: D"
else
  echo "Grade: F"
fi

Best practices:

  • Test most likely conditions first for efficiency

  • Use clear, simple conditions

  • Avoid deeply nested if/elif chains (use case instead)

7.1.3.2. if/else#

if [ condition ]; then
  # runs if true
else
  # runs if false
fi

Real example:

#!/bin/bash
age=$1

if [ $age -ge 18 ]; then
  echo "You are an adult"
else
  echo "You are a minor"
fi

7.1.3.3. Basic if#

if [ condition ]; then
  # code runs if condition is true
fi

Real example:

#!/bin/bash
file="$1"

if [ -f "$file" ]; then
  echo "File exists"
  wc -l "$file"
fi

7.1.4. if/elif/else: Sequential Decision Making#

Test conditions in order and execute the first one that matches: