Bash Case Statement

A case statement compares one value against a list of patterns and runs the code of the first match. It replaces long chains of if and elif lines and keeps menu-style scripts tidy.

A Railway Signal Analogy

A railway signal shows red, yellow, or green. The driver reads the color and picks one action: stop, slow down, or go. A case statement reads a value and picks one block of code in the same way.

              +-----------------+
              |  value: $color  |
              +--------+--------+
                       |
        +--------------+--------------+
        |              |              |
        v              v              v
     "red"          "yellow"       "green"
     Stop           Slow down        Go

Basic Syntax

case value in
  pattern1)
    commands
    ;;
  pattern2)
    commands
    ;;
  *)
    default commands
    ;;
esac

Each block ends with ;;. The word esac (case spelled backward) closes the whole statement. The * pattern catches every value that matched nothing before it.

Example: Traffic Signal

#!/bin/bash
read -p "Enter signal color: " color

case $color in
  red)
    echo "Stop the vehicle"
    ;;
  yellow)
    echo "Slow down"
    ;;
  green)
    echo "Go ahead"
    ;;
  *)
    echo "Unknown color"
    ;;
esac

Output (input: green):

Go ahead

Match Several Patterns in One Block

The pipe symbol | means "or". Use it to share one block between several values.

#!/bin/bash
read -p "Answer yes or no: " reply

case $reply in
  y|Y|yes|YES)
    echo "You agreed"
    ;;
  n|N|no|NO)
    echo "You declined"
    ;;
  *)
    echo "Please type yes or no"
    ;;
esac

Use Wildcards in Patterns

Patterns support the same wildcards as file names. The star matches any text, the question mark matches one character, and square brackets match a set.

#!/bin/bash
file=$1

case $file in
  *.txt)
    echo "Text document"
    ;;
  *.jpg|*.png)
    echo "Image file"
    ;;
  *.sh)
    echo "Shell script"
    ;;
  [0-9]*)
    echo "Name starts with a digit"
    ;;
  *)
    echo "Unknown file type"
    ;;
esac

Run ./type.sh photo.png and the screen shows Image file.

Build a Simple Menu

#!/bin/bash
echo "1) Show date"
echo "2) Show folder"
echo "3) Show user"
echo "4) Exit"
read -p "Choose an option: " choice

case $choice in
  1) date ;;
  2) pwd ;;
  3) whoami ;;
  4) echo "Goodbye" ;;
  *) echo "Invalid choice" ;;
esac

Short commands fit on one line with ;; at the end. Longer blocks work better with one command per line.

Handle Command Line Actions

Service scripts often accept words like start and stop:

#!/bin/bash
case $1 in
  start)
    echo "Starting service..."
    ;;
  stop)
    echo "Stopping service..."
    ;;
  restart)
    echo "Restarting service..."
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
    ;;
esac

Case Versus If

SituationBetter Choice
One value, many fixed optionscase
Number comparisons such as greater thanif
Pattern checks on file namescase
Several different conditions combinedif

Common Mistakes

  • A missing ;; merges two blocks into a syntax error.
  • A *) pattern placed first catches every value and blocks the others.
  • Spaces inside patterns need quotation marks, such as "New York").
  • Case compares text only. Use if with -gt or -lt for number ranges.

Key Takeaways

  • case picks one block from a list of patterns.
  • Each block ends with ;;, and the statement ends with esac.
  • Use | to join several patterns and *) for the default block.
  • Wildcards make file type checks short and readable.
  • Menus and service scripts use case statements often.