Case Statements
Case statements provide a cleaner, more readable alternative to long if-elif chains when checking a single variable against multiple values. They're perfect for menu systems, command parsing, file type detection, and any situation where you need multi-way branching based on a single value. Case statements use pattern matching, making them more powerful than simple equality checks!
Basic Case Statement Syntax
A case statement starts with case, tests a value against patterns, and ends with esac (case spelled backwards). Each pattern is followed by ) and ends with ;;.
Click Run to execute your code
# Basic syntax
case variable in
pattern1)
# code for pattern1
;;
pattern2)
# code for pattern2
;;
*)
# default case (optional)
;;
esac
# Example
choice="yes"
case $choice in
yes|y|YES|Y)
echo "You chose yes"
;;
no|n|NO|N)
echo "You chose no"
;;
*)
echo "Invalid choice"
;;
esac
-
case starts, esac ends (case backwards)- Each pattern ends with
)- Each case block ends with
;; (double semicolon)-
*) is the default case (matches anything)- Patterns use glob matching (not regex)
Pattern Matching
Case statements support glob patterns, making them powerful for matching multiple values and ranges.
| Pattern | Description | Example |
|---|---|---|
* |
Matches any string | *.txt matches any .txt file |
? |
Matches any single character | file?.txt matches file1.txt, fileA.txt |
[] |
Character class - matches one character from set | [0-9] matches any digit |
| |
OR - matches if any pattern matches | yes|y|YES matches any of these |
* (default) |
Default case (match anything) | *) catch-all case |
# File extension check
filename="image.jpg"
case $filename in
*.jpg|*.jpeg)
echo "JPEG image"
;;
*.png)
echo "PNG image"
;;
*.gif)
echo "GIF image"
;;
*)
echo "Unknown file type"
;;
esac
# Character class example
char="a"
case $char in
[a-z])
echo "Lowercase letter"
;;
[A-Z])
echo "Uppercase letter"
;;
[0-9])
echo "Digit"
;;
*)
echo "Other character"
;;
esac
Multiple Patterns
You can combine multiple patterns using | (pipe) to match any of them. This is cleaner than separate if-elif conditions.
# Multiple patterns with |
action="START"
case $action in
start|START|begin|BEGIN)
echo "Starting service..."
;;
stop|STOP|halt|HALT)
echo "Stopping service..."
;;
restart|RESTART|reboot|REBOOT)
echo "Restarting service..."
;;
*)
echo "Unknown action"
;;
esac
Practical Examples
Case statements are commonly used in real-world scripts:
# Menu system
PS3="Choose an option: "
read choice
case $choice in
1)
echo "Starting..."
;;
2)
echo "Stopping..."
;;
3)
echo "Restarting..."
;;
q|Q|quit|QUIT)
echo "Exiting..."
exit 0
;;
*)
echo "Invalid option"
;;
esac
# Command parsing
command="$1"
case $command in
install|i)
echo "Installing..."
;;
uninstall|remove|r)
echo "Uninstalling..."
;;
status|s)
echo "Checking status..."
;;
*)
echo "Usage: script.sh [install|uninstall|status]"
exit 1
;;
esac
Common Mistakes
1. Missing double semicolon (;;)
# Wrong - missing ;;
case $var in
pattern1)
echo "Matched"
# Missing ;; causes fall-through!
pattern2)
echo "Also matches"
;;
esac
# Correct - each case ends with ;;
case $var in
pattern1)
echo "Matched"
;; # Required!
pattern2)
echo "Also matches"
;;
esac
2. Using == instead of pattern matching
# Wrong - == doesn't work in case
case $var in
== "value") # Syntax error
echo "Match"
;;
esac
# Correct - just use the pattern
case $var in
value) # Matches exact string
echo "Match"
;;
"value with spaces") # Quote if needed
echo "Match"
;;
esac
3. Confusing glob patterns with regex
# Case uses GLOB patterns, not regex
filename="test123.txt"
# Correct - glob patterns
case $filename in
test*.txt) # Matches test, then any chars, then .txt
echo "Match"
;;
esac
# Wrong - regex syntax doesn't work
case $filename in
test[0-9]+.txt) # + doesn't work in glob
echo "Won't match as expected"
;;
esac
Exercise: Create a File Type Detector
Task: Create a script that detects file types using case statements!
Requirements:
- Use a case statement to check file extension
- Handle at least 4 different file types (e.g., images, documents, scripts)
- Use pattern matching with wildcards
- Include a default case for unknown types
- Support multiple extensions for same type (e.g., jpg and jpeg)
Show Solution
#!/bin/bash
# File type detector
filename="$1"
case "$filename" in
*.jpg|*.jpeg|*.JPG|*.JPEG)
echo "$filename: JPEG image"
;;
*.png|*.PNG)
echo "$filename: PNG image"
;;
*.sh|*.bash)
echo "$filename: Shell script"
;;
*.py)
echo "$filename: Python script"
;;
*.txt|*.md|*.log)
echo "$filename: Text file"
;;
*)
echo "$filename: Unknown file type"
;;
esac
Summary
- Syntax:
case variable in pattern) ... ;; esac - Patterns: Use glob patterns (*, ?, []) not regex
- Multiple: Combine patterns with
|(pipe) - Ending: Each case ends with
;;(double semicolon) - Default: Use
*)for catch-all case - Closing: End with
esac(case backwards) - Use When: Checking single variable against multiple values
- Advantage: Cleaner than long if-elif chains
What's Next?
Excellent! Case statements make multi-way decisions much cleaner. Next, we'll dive into For Loops - one of the most commonly used control structures for iterating over lists, arrays, files, and ranges. You'll learn different for loop styles and when to use each!
Enjoying these tutorials?