The case Statement — Multi-Way Branching
The case statement is Bash's pattern-matching switch. Use it to write cleaner multi-branch logic than chains of if/elif — especially for string matching and option parsing.
When you have many possible values for a variable and need to branch on each, a chain of elif statements becomes unwieldy. The case statement provides a cleaner pattern-matching alternative, similar to switch in C or JavaScript — but with glob patterns.
Basic case Syntax
case "$variable" in
pattern1)
# commands for pattern1
;; # <-- two semicolons end each block
pattern2)
# commands for pattern2
;;
pattern3 | pattern4) # multiple patterns with |
# commands for pattern3 OR pattern4
;;
*) # default — matches anything
# fallback commands
;;
esac # closes case (backwards: "esac")Practical Examples
#!/usr/bin/env bash
# Day type checker
day=$(date +%A) # full day name: Monday, Tuesday, ...
case "$day" in
Monday | Tuesday | Wednesday | Thursday | Friday)
echo "It's a weekday"
;;
Saturday | Sunday)
echo "It's the weekend!"
;;
*)
echo "Unknown day: $day"
;;
esac#!/usr/bin/env bash
# Simple CLI menu
read -rp "Choose action [start|stop|restart|status]: " action
case "$action" in
start)
echo "Starting service..."
;;
stop)
echo "Stopping service..."
;;
restart)
echo "Restarting service..."
;;
status)
echo "Checking status..."
;;
*)
echo "Invalid action: $action" >&2
echo "Valid: start, stop, restart, status" >&2
exit 1
;;
esacPattern Matching in case
case uses glob patterns (the same as filename matching), not regex:
filename="report_2026.csv"
case "$filename" in
*.csv)
echo "CSV file"
;;
*.txt | *.md)
echo "Text file"
;;
*.tar.gz | *.tgz)
echo "Compressed archive"
;;
[0-9]*)
echo "Starts with a digit"
;;
*)
echo "Unknown type"
;;
esacFall-through with ;& and ;;&
By default, case stops after the first matching pattern (unlike C's switch). Bash 4 adds fall-through terminators:
case terminators
| Terminator | Behaviour |
|---|---|
;; | Stop — don't check remaining patterns (default) |
;& | Fall-through — execute next pattern's block unconditionally |
;;& | Continue testing — check remaining patterns for more matches |
level=3
case "$level" in
3)
echo "Level 3 specific setup"
;;& # continue testing other patterns
[2-3])
echo "Common setup for level 2 and 3"
;;&
[1-3])
echo "Setup for levels 1, 2, and 3"
;;
esac
# Output for level=3:
# Level 3 specific setup
# Common setup for level 2 and 3
# Setup for levels 1, 2, and 3What do the two semicolons `;;` at the end of a case pattern block do?
Write a script file-action.sh that takes a filename as argument. Use case to:
.shfiles → print "Running shell script..." and execute it withbash.pyfiles → print "Running Python script..." and execute withpython3.txtor.md→ print the file contents withcat- Anything else → print "Don't know how to run: filename"