Linux CLI 63 ๐ง case command in shell scripts
#!/bin/bash
read -p "Enter your favorite fruit (apple, banana, or orange): " fruit
case $fruit in
apple)
echo "You like apples!"
;;
banana)
echo "You like bananas!"
;;
orange)
echo "You like oranges!"
;;
*)
echo "I don't know that fruit."
;;
esac
read -p "Enter your favorite fruit: " fruit
case $fruit in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
When you have one value to check against many possible patterns, a chain of if/elif/else gets ugly fast. The case statement is the cleaner alternative โ it matches a value against a list of patterns and runs the first block that matches.
Key point: case compares a single value against multiple patterns. Each pattern ends with ;;. The first match wins. The * pattern at the end is the default โ it catches anything that didn’t match earlier.
a – case command introduction
The case statement is used for conditional execution based on the value of a variable or expression. It provides a more readable and compact alternative to multiple if–elif–else statements when you have a limited set of possible values to check against.
Syntax:
case variable in
pattern1)
# commands if variable matches pattern1
;;
pattern2)
# commands if variable matches pattern2
;;
pattern3)
# commands if variable matches pattern3
;;
*)
# commands if none of the above patterns match
;;
esac
Breaking it down:
variableis the value you want to checkpattern1,pattern2, etc. are the values or patterns you want to match against;;separates each pattern block*is a wildcard that matches any other case not explicitly listed
Basic example โ favorite fruit:
#!/bin/bash
read -p "Enter your favorite fruit (apple, banana, or orange): " fruit
case $fruit in
apple)
echo "You like apples!"
;;
banana)
echo "You like bananas!"
;;
orange)
echo "You like oranges!"
;;
*)
echo "I don't know that fruit."
;;
esac
$ ./fruit.sh
Enter your favorite fruit (apple, banana, or orange): apple
[ You like apples! ]
$ ./fruit.sh
Enter your favorite fruit (apple, banana, or orange): banana
[ You like bananas! ]
$ ./fruit.sh
Enter your favorite fruit (apple, banana, or orange): kiwi
[ I don't know that fruit. ]
How it flows:
- The
casestatement checks the value offruitagainst several patterns (apple,banana,orange) - If
fruitmatches one of these patterns, the corresponding block runs - If none match, the
*pattern’s block runs
case vs if/elif/else:
| Aspect | case | if/elif/else |
|---|---|---|
| Checks | One value against many patterns | Many independent conditions |
| Readability | Clean for many options | Gets verbose fast |
| Pattern matching | Globs, classes, alternatives | Regex or globs via [[ ]] |
| Fall-through | No (each block is isolated) | No |
| Default | *) | else |
| Best for | Menus, options, dispatch | Complex conditions |
The same logic both ways:
# With if/elif/else
if [ "$fruit" = "apple" ]; then
echo "You like apples!"
elif [ "$fruit" = "banana" ]; then
echo "You like bananas!"
elif [ "$fruit" = "orange" ]; then
echo "You like oranges!"
else
echo "I don't know that fruit."
fi
# With case โ cleaner
case $fruit in
apple) echo "You like apples!" ;;
banana) echo "You like bananas!" ;;
orange) echo "You like oranges!" ;;
*) echo "I don't know that fruit." ;;
esac
For three options, if is fine. For ten, case wins hands-down.
The ;; terminator:
Each block ends with ;;. It’s like break in C’s switch โ it stops execution of the case after a match. Without it, the shell would keep checking the following patterns.
case $x in
a) echo "A" ;; # โ the ;; ends this block
b) echo "B" ;;
c) echo "C" ;;
esac
Note: In bash,
;;∧&are alternatives that allow fall-through or continued testing, but;;is what you’ll use 99% of the time.
Case is exact-match by default:
$ fruit="Apple"
$ case $fruit in
> apple) echo "match" ;;
> *) echo "no match" ;;
> esac
[ no match ]
Apple doesn’t match apple โ case-sensitive. Use a character class to be flexible:
case $fruit in
[Aa]pple) echo "match" ;;
esac
Case with no default:
case $x in
a) echo "A" ;;
b) echo "B" ;;
esac
If x is neither a nor b, nothing happens. This is fine โ but often you want a default to catch typos.
A practical example โ service control:
#!/bin/bash
case "$1" in
start)
echo "Starting service..."
# systemctl start myservice
;;
stop)
echo "Stopping service..."
# systemctl stop myservice
;;
restart)
echo "Restarting service..."
# systemctl restart myservice
;;
status)
echo "Checking status..."
# systemctl status myservice
;;
*)
echo "Usage: $0 {start|stop|restart|status}" >&2
exit 1
;;
esac
This is the classic pattern for command-line tools.
A menu with case:
#!/bin/bash
while true; do
echo "1) Show date"
echo "2) Show uptime"
echo "3) Show disk"
echo "4) Quit"
read -p "Choice: " choice
case "$choice" in
1) date ;;
2) uptime ;;
3) df -h ;;
4) echo "Goodbye"; break ;;
*) echo "Invalid choice" ;;
esac
done
b – case command and patterns
case supports several kinds of patterns โ not just literal strings. This is where it becomes more powerful than a chain of [ "$x" = "y" ] tests.
Common pattern types:
- Simple strings
- Wildcards
- Character classes
- Alternatives
- Default
1. Simple strings:
case "$fruit" in
apple) echo "apple" ;;
banana) echo "banana" ;;
esac
Exact match, case-sensitive.
2. Wildcards:
Use * to match any sequence of characters, and ? to match any single character:
case "$fruit" in
a*) echo "Starts with a" ;;
*e) echo "Ends with e" ;;
?????) echo "Exactly five characters" ;;
*) echo "Anything else" ;;
esac
| Wildcard | Meaning |
|---|---|
* | Any sequence (including empty) |
? | Any single character |
[abc] | Any one of a, b, c |
[a-z] | Any character in range |
[!abc] | Any character NOT in the set |
3. Character classes:
POSIX classes work inside [ ... ]:
case "$input" in
[[:digit:]]*) echo "Starts with a digit" ;;
[[:upper:]]*) echo "Starts with uppercase" ;;
[[:lower:]]*) echo "Starts with lowercase" ;;
[[:space:]]*) echo "Starts with whitespace" ;;
esac
Available classes:
| Class | Matches |
|---|---|
[[:upper:]] | Uppercase letters |
[[:lower:]] | Lowercase letters |
[[:alpha:]] | Letters |
[[:digit:]] | Digits |
[[:alnum:]] | Letters and digits |
[[:space:]] | Whitespace |
[[:punct:]] | Punctuation |
[[:graph:]] | Printable, non-space |
[[:xdigit:]] | Hex digits |
4. Alternatives with |:
Match multiple patterns in one block:
case "$fruit" in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
The full example from the top of the chapter:
#!/bin/bash
read -p "Enter your favorite fruit: " fruit
case $fruit in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
$ ./fruit.sh
Enter your favorite fruit: apple
[ You like apples or apricots! ]
$ ./fruit.sh
Enter your favorite fruit: apricot
[ You like apples or apricots! ]
$ ./fruit.sh
Enter your favorite fruit: banana
[ You like bananas or something that starts with 'banano'. ]
$ ./fruit.sh
Enter your favorite fruit: bananofoo
[ You like bananas or something that starts with 'banano'. ]
$ ./fruit.sh
Enter your favorite fruit: orange
[ You like oranges or maybe a misspelling of 'orange'. ]
$ ./fruit.sh
Enter your favorite fruit: Orange
[ You like oranges or maybe a misspelling of 'orange'. ]
$ ./fruit.sh
Enter your favorite fruit: kiwi
[ I don't know that fruit. ]
Each block combines:
- Literal alternatives โ
apple|apricot - Wildcards โ
banano* - Character classes โ
[Oo]range
5. The default pattern *:
The final *) catches anything that didn’t match earlier:
case "$x" in
1) echo "one" ;;
2) echo "two" ;;
*) echo "something else" ;; # default
esac
Without *), unmatched values just fall through silently:
$ x=99
$ case "$x" in
> 1) echo "one" ;;
> 2) echo "two" ;;
> esac
$ echo $?
[ 0 ]
Nothing printed โ no error. Adding *) makes the behavior explicit.
Tip: Always include a
*)default unless you have a specific reason not to. It catches typos and gives you a place to show a usage message.
Putting it all together โ a dispatch script:
#!/bin/bash
case "$1" in
start|up|begin)
echo "Starting..."
;;
stop|down|halt)
echo "Stopping..."
;;
restart|reload)
echo "Restarting..."
;;
status|info)
echo "Status..."
;;
*.txt)
echo "Text file: $1"
;;
*.log)
echo "Log file: $1"
;;
[0-9]*)
echo "Starts with a digit: $1"
;;
"")
echo "No argument given" >&2
exit 1
;;
*)
echo "Unknown command: $1" >&2
exit 1
;;
esac
$ ./dispatch.sh start
[ Starting... ]
$ ./dispatch.sh restart
[ Restarting... ]
$ ./dispatch.sh report.txt
[ Text file: report.txt ]
$ ./dispatch.sh 42things
[ Starts with a digit: 42things ]
$ ./dispatch.sh
[ No argument given ]
$ ./dispatch.sh frobnicate
[ Unknown command: frobnicate ]
Case with fall-through using ;;& (bash 4+):
Normally ;; stops after the first match. ;;& continues testing the following patterns โ useful for multiple matches:
$ x="apple"
$ case "$x" in
> a*) echo "starts with a" ;;&
> *e) echo "ends with e" ;;&
> apple) echo "is apple" ;;
> esac
[ starts with a ]
[ ends with e ]
[ is apple ]
And ;& falls through to the next block without testing:
$ case "a" in
> a) echo "A" ;&
> b) echo "B" ;;
> esac
[ A ]
[ B ]
These are bash-specific โ not POSIX. Use them only when you need fall-through behavior.
Case with a variable pattern:
$ pattern="app*"
$ case "apple" in
> $pattern) echo "match" ;;
> esac
[ match ]
The pattern can come from a variable. This is useful for dynamic dispatch.
Case in a function:
check_os() {
case "$(uname -s)" in
Linux*) echo "Linux" ;;
Darwin*) echo "macOS" ;;
CYGWIN*) echo "Cygwin" ;;
MINGW*) echo "MinGW" ;;
*) echo "Unknown" ;;
esac
}
$ check_os
[ Linux ]
A common real-world use โ file type detection:
for file in *; do
case "$file" in
*.txt) echo "$file: text" ;;
*.jpg|*.png) echo "$file: image" ;;
*.sh) echo "$file: script" ;;
*.tar.gz) echo "$file: archive" ;;
*) echo "$file: unknown" ;;
esac
done
Complete Example Session
# ============================================
# PART 1: BASIC CASE
# ============================================
$ cat > fruit.sh << 'EOF'
#!/bin/bash
read -p "Enter your favorite fruit (apple, banana, or orange): " fruit
case $fruit in
apple)
echo "You like apples!"
;;
banana)
echo "You like bananas!"
;;
orange)
echo "You like oranges!"
;;
*)
echo "I don't know that fruit."
;;
esac
EOF
$ chmod +x fruit.sh
$ ./fruit.sh
Enter your favorite fruit (apple, banana, or orange): apple
[ You like apples! ]
$ ./fruit.sh
Enter your favorite fruit (apple, banana, or orange): banana
[ You like bananas! ]
$ ./fruit.sh
Enter your favorite fruit (apple, banana, or orange): kiwi
[ I don't know that fruit. ]
# ============================================
# PART 2: CASE WITH PATTERNS
# ============================================
$ cat > fruit2.sh << 'EOF'
#!/bin/bash
read -p "Enter your favorite fruit: " fruit
case $fruit in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
EOF
$ chmod +x fruit2.sh
$ ./fruit2.sh
Enter your favorite fruit: apricot
[ You like apples or apricots! ]
$ ./fruit2.sh
Enter your favorite fruit: bananofoo
[ You like bananas or something that starts with 'banano'. ]
$ ./fruit2.sh
Enter your favorite fruit: Orange
[ You like oranges or maybe a misspelling of 'orange'. ]
# ============================================
# PART 3: SERVICE CONTROL
# ============================================
$ cat > service.sh << 'EOF'
#!/bin/bash
case "$1" in
start) echo "Starting..." ;;
stop) echo "Stopping..." ;;
restart) echo "Restarting..." ;;
status) echo "Status..." ;;
*)
echo "Usage: $0 {start|stop|restart|status}" >&2
exit 1
;;
esac
EOF
$ chmod +x service.sh
$ ./service.sh start
[ Starting... ]
$ ./service.sh restart
[ Restarting... ]
$ ./service.sh frobnicate
[ Usage: ./service.sh {start|stop|restart|status} ]
# ============================================
# PART 4: CHARACTER CLASSES
# ============================================
$ for x in 1abc ABCdef abc123 " spaced" "!hello"; do
> case "$x" in
> [[:digit:]]*) echo "$x โ starts with digit" ;;
> [[:upper:]]*) echo "$x โ starts with uppercase" ;;
> [[:lower:]]*) echo "$x โ starts with lowercase" ;;
> [[:space:]]*) echo "$x โ starts with space" ;;
> *) echo "$x โ other" ;;
> esac
> done
[ 1abc โ starts with digit ]
[ ABCdef โ starts with uppercase ]
[ abc123 โ starts with lowercase ]
[ spaced โ starts with space ]
[ !hello โ other ]
# ============================================
# PART 5: FILE TYPE DETECTION
# ============================================
$ for file in report.txt photo.jpg script.sh archive.tar.gz data.bin; do
> case "$file" in
> *.txt) echo "$file: text" ;;
> *.jpg|*.png) echo "$file: image" ;;
> *.sh) echo "$file: script" ;;
> *.tar.gz) echo "$file: archive" ;;
> *) echo "$file: unknown" ;;
> esac
> done
[ report.txt: text ]
[ photo.jpg: image ]
[ script.sh: script ]
[ archive.tar.gz: archive ]
[ data.bin: unknown ]
# ============================================
# PART 6: MENU WITH CASE
# ============================================
$ cat > menu.sh << 'EOF'
#!/bin/bash
while true; do
echo "1) Date"
echo "2) Uptime"
echo "3) Disk"
echo "4) Quit"
read -p "Choice: " c
case "$c" in
1) date ;;
2) uptime ;;
3) df -h / ;;
4) echo "Bye"; break ;;
*) echo "Invalid choice" ;;
esac
echo
done
EOF
$ chmod +x menu.sh
$ ./menu.sh
[ 1) Date ]
[ 2) Uptime ]
[ 3) Disk ]
[ 4) Quit ]
Choice: 1
[ Mon Jan 15 10:00:00 UTC 2024 ]
[ 1) Date ]
[ 2) Uptime ]
[ 3) Disk ]
[ 4) Quit ]
Choice: 4
[ Bye ]
# ============================================
# PART 7: OS DETECTION
# ============================================
$ cat > os.sh << 'EOF'
#!/bin/bash
case "$(uname -s)" in
Linux*) echo "Linux" ;;
Darwin*) echo "macOS" ;;
CYGWIN*) echo "Cygwin" ;;
MINGW*) echo "MinGW" ;;
*) echo "Unknown" ;;
esac
EOF
$ chmod +x os.sh
$ ./os.sh
[ Linux ]
# ============================================
# PART 8: YES/NO CONFIRMATION
# ============================================
$ read -p "Continue? (y/n): " ans
Continue? (y/n): y
$ case "$ans" in
> [Yy]|[Yy]es|YES) echo "Continuing" ;;
> [Nn]|[Nn]o|NO) echo "Cancelled" ;;
> *) echo "Please answer y or n" ;;
> esac
[ Continuing ]
# ============================================
# PART 9: CASE WITH FALL-THROUGH (bash 4+)
# ============================================
$ x="apple"
$ case "$x" in
> a*) echo "starts with a" ;;&
> *e) echo "ends with e" ;;&
> apple) echo "is apple" ;;
> esac
[ starts with a ]
[ ends with e ]
[ is apple ]
# ============================================
# PART 10: EMPTY INPUT
# ============================================
$ read -p "Name: " name
Name:
$ case "$name" in
> "") echo "Empty input" ;;
> *) echo "Hello, $name" ;;
> esac
[ Empty input ]
# ============================================
# PART 11: COMBINING PATTERNS
# ============================================
$ for x in a b c d e; do
> case "$x" in
> a|b|c) echo "$x: in first group" ;;
> d|e) echo "$x: in second group" ;;
> *) echo "$x: other" ;;
> esac
> done
[ a: in first group ]
[ b: in first group ]
[ c: in first group ]
[ d: in second group ]
[ e: in second group ]
# ============================================
# PART 12: FULL EXAMPLE
# ============================================
$ cat > full.sh << 'EOF'
#!/bin/bash
read -p "Enter your favorite fruit (apple, banana, or orange): " fruit
case $fruit in
apple)
echo "You like apples!"
;;
banana)
echo "You like bananas!"
;;
orange)
echo "You like oranges!"
;;
*)
echo "I don't know that fruit."
;;
esac
read -p "Enter your favorite fruit: " fruit
case $fruit in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
EOF
$ chmod +x full.sh
$ ./full.sh
Enter your favorite fruit (apple, banana, or orange): apple
[ You like apples! ]
Enter your favorite fruit: apricot
[ You like apples or apricots! ]
Quick Reference
case Syntax
| Part | Meaning |
|---|---|
case $var in | Start the case |
pattern) | Start a block |
;; | End a block |
*) | Default |
esac | End the case |
Pattern Types
| Pattern | Matches |
|---|---|
apple | Literal string |
a* | Starts with a |
*e | Ends with e |
????? | Exactly 5 chars |
[abc] | Any of a, b, c |
[a-z] | Any lowercase |
[!abc] | Not a, b, c |
apple|apricot | Either |
* | Anything |
Character Classes
| Class | Matches |
|---|---|
[[:upper:]] | Uppercase |
[[:lower:]] | Lowercase |
[[:alpha:]] | Letters |
[[:digit:]] | Digits |
[[:alnum:]] | Letters + digits |
[[:space:]] | Whitespace |
[[:punct:]] | Punctuation |
[[:xdigit:]] | Hex digits |
Terminators
| Terminator | Effect |
|---|---|
;; | Stop after match |
;& | Fall through to next block (bash) |
;;& | Continue testing patterns (bash) |
case vs if
| Use case when | Use if when |
|---|---|
| One value, many patterns | Many independent conditions |
| Matching strings, globs, classes | Comparing numbers, files |
| Menu / dispatch | Complex boolean logic |
Patterns like *.txt | Regex via [[ =~ ]] |
Best Practices
โ Do This:
# Always include a default
case "$x" in
a) echo "A" ;;
*) echo "Unknown" ;;
esac # โ
# Quote the variable
case "$x" in ... esac # โ
# Use alternatives for related patterns
case "$x" in
start|up|begin) echo "Starting" ;;
esac # โ
# Use | for case-insensitive yes/no
case "$ans" in
[Yy]|[Yy]es) echo "yes" ;;
[Nn]|[Nn]o) echo "no" ;;
esac # โ
# Use for file extension dispatch
case "$file" in
*.txt) echo "text" ;;
*.jpg) echo "image" ;;
esac # โ
# Show usage on bad input
case "$1" in
start) ... ;;
*) echo "Usage: $0 {start}" >&2; exit 1 ;;
esac # โ
# Use a variable for dynamic patterns
case "$x" in
$pattern) echo "match" ;;
esac # โ
โ Don’t Do This:
# Don't forget the ;;
case "$x" in
a) echo "A"
b) echo "B" # โ syntax error
esac
# Don't forget esac
case "$x" in
a) echo "A" ;;
# โ missing esac
# Don't use case for numeric comparisons
case "$n" in
1) echo "one" ;;
>5) echo "big" # โ no > in patterns
esac
# Don't rely on case being case-insensitive
case "$x" in
apple) ... # โ ๏ธ won't match "Apple"
esac
# Don't forget the pipe for alternatives
case "$x" in
start stop) ... # โ matches literal "start stop"
start|stop) ... # โ
# Don't omit default on user input
case "$input" in
yes) ... ;;
esac # โ ๏ธ typo goes unnoticed
# Don't use bash-only features in sh
#!/bin/sh
case "$x" in
a) echo "A" ;;& # โ not POSIX
esac
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
Missing ;; | Syntax error | Add terminator |
Missing esac | Syntax error | Add closing keyword |
| Unquoted variable | Word splitting | Quote: "$x" |
| Case-sensitive | “Apple” โ “apple” | Use [Aa]pple |
| No default | Silent on no match | Add *) |
> in patterns | Not supported | Use [[ ]] or if |
| Literal space in pattern | Matches space | Watch whitespace |
Forgot | | Pattern literal | Use a|b |
Real-World Examples
1. Basic Fruit Match
#!/bin/bash
read -p "Enter your favorite fruit (apple, banana, or orange): " fruit
case $fruit in
apple)
echo "You like apples!"
;;
banana)
echo "You like bananas!"
;;
orange)
echo "You like oranges!"
;;
*)
echo "I don't know that fruit."
;;
esac
2. Fruit with Alternatives
#!/bin/bash
read -p "Enter your favorite fruit: " fruit
case $fruit in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
3. Service Control
#!/bin/bash
case "$1" in
start) echo "Starting service..." ;;
stop) echo "Stopping service..." ;;
restart) echo "Restarting service..." ;;
status) echo "Checking status..." ;;
*)
echo "Usage: $0 {start|stop|restart|status}" >&2
exit 1
;;
esac
4. Yes/No Confirmation
#!/bin/bash
read -p "Continue? (y/n): " ans
case "$ans" in
[Yy]|[Yy]es) echo "Continuing" ;;
[Nn]|[Nn]o) echo "Cancelled" ;;
*) echo "Please answer y or n" ;;
esac
5. File Extension
#!/bin/bash
for file in *; do
case "$file" in
*.txt) echo "$file: text" ;;
*.jpg|*.png) echo "$file: image" ;;
*.sh) echo "$file: script" ;;
*.tar.gz) echo "$file: archive" ;;
*) echo "$file: unknown" ;;
esac
done
6. Menu
#!/bin/bash
while true; do
echo "1) Date"
echo "2) Uptime"
echo "3) Quit"
read -p "Choice: " c
case "$c" in
1) date ;;
2) uptime ;;
3) break ;;
*) echo "Invalid" ;;
esac
done
7. OS Detection
#!/bin/bash
case "$(uname -s)" in
Linux*) echo "Linux" ;;
Darwin*) echo "macOS" ;;
CYGWIN*) echo "Cygwin" ;;
MINGW*) echo "MinGW" ;;
*) echo "Unknown" ;;
esac
8. Handle Empty Input
#!/bin/bash
read -p "Name: " name
case "$name" in
"") echo "Empty input" ;;
*) echo "Hello, $name" ;;
esac
9. Log Level Filter
#!/bin/bash
level="$1"
case "$level" in
debug|DEBUG) echo "Debug mode" ;;
info|INFO) echo "Info mode" ;;
warn|WARN) echo "Warning mode" ;;
error|ERROR) echo "Error mode" ;;
*) echo "Unknown level" >&2; exit 1 ;;
esac
10. Extension Routing
#!/bin/bash
file="$1"
case "$file" in
*.tar.gz|*.tgz) tar -xzf "$file" ;;
*.tar.bz2) tar -xjf "$file" ;;
*.zip) unzip "$file" ;;
*.gz) gunzip "$file" ;;
*) echo "Unknown archive: $file" >&2; exit 1 ;;
esac
11. Version Check
#!/bin/bash
case "$(uname -r)" in
5.*) echo "Modern kernel" ;;
4.*) echo "Older kernel" ;;
*) echo "Ancient kernel" ;;
esac
12. Git Hook
#!/bin/bash
case "$1" in
commit) echo "Running pre-commit checks..." ;;
push) echo "Running pre-push checks..." ;;
*) echo "Unknown hook: $1" ;;
esac
13. Colors
#!/bin/bash
color="$1"
case "$color" in
red) echo -e "\033[31mRed\033[0m" ;;
green) echo -e "\033[32mGreen\033[0m" ;;
blue) echo -e "\033[34mBlue\033[0m" ;;
*) echo "Unknown color" ;;
esac
14. Filename Classification
#!/bin/bash
for f in *; do
case "$f" in
.*) echo "$f: hidden" ;;
*.bak) echo "$f: backup" ;;
*~) echo "$f: temp" ;;
*.log) echo "$f: log" ;;
*) echo "$f: regular" ;;
esac
done
15. Cleanup by Type
#!/bin/bash
for f in *; do
case "$f" in
*.tmp|*.swp|*~)
echo "Removing $f"
rm -f "$f"
;;
esac
done
16. Parse Command-Line Option
#!/bin/bash
case "$1" in
-h|--help) echo "Help text" ;;
-v|--version) echo "Version 1.0" ;;
-d|--debug) set -x ;;
*) echo "Unknown option" ;;
esac
17. Prompt Loop Until Valid
#!/bin/bash
while true; do
read -p "Choose (a/b/c): " c
case "$c" in
a|A) echo "You chose A"; break ;;
b|B) echo "You chose B"; break ;;
c|C) echo "You chose C"; break ;;
*) echo "Invalid, try again" ;;
esac
done
18. Case in a Function
#!/bin/bash
http_status() {
case "$1" in
200) echo "OK" ;;
301) echo "Moved Permanently" ;;
404) echo "Not Found" ;;
500) echo "Internal Server Error" ;;
*) echo "Unknown status" ;;
esac
}
http_status 200
http_status 404
[ OK ]
[ Not Found ]
19. Bash Fall-Through
#!/bin/bash
x="apple"
case "$x" in
a*) echo "starts with a" ;;&
*e) echo "ends with e" ;;&
apple) echo "is apple" ;;
esac
[ starts with a ]
[ ends with e ]
[ is apple ]
20. Full Combined Example
#!/bin/bash
read -p "Enter your favorite fruit (apple, banana, or orange): " fruit
case $fruit in
apple)
echo "You like apples!"
;;
banana)
echo "You like bananas!"
;;
orange)
echo "You like oranges!"
;;
*)
echo "I don't know that fruit."
;;
esac
read -p "Enter your favorite fruit: " fruit
case $fruit in
apple|apricot)
echo "You like apples or apricots!"
;;
banana|banano*)
echo "You like bananas or something that starts with 'banano'."
;;
orange|[Oo]range)
echo "You like oranges or maybe a misspelling of 'orange'."
;;
*)
echo "I don't know that fruit."
;;
esac
Visual: How case Works
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ case $fruit in โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ "apple" โ โ
โ โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ match? โโโดโโ no โโโ โ
โ โ โ โ
โ yes โผ โ
โ โ โโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ "banana" โ โ
โ โ โโโโโโโโโโโฌโโโโโโโโโโโ โ
โ โ โ โ
โ โ match? โโโดโโ no โโโ โ
โ โ โ โ โ
โ โ yes โผ โ
โ โ โ โโโโโโโโโโโโโโ โ
โ โ โ โ "orange" โ โ
โ โ โ โโโโโโโฌโโโโโโโ โ
โ โ โ โ โ
โ โ โ match? โโโดโ no โโ โ
โ โ โ โ โ โ
โ โ โ yes โผ โ
โ โ โ โ โโโโโโโโโโ
โ โ โ โ โ * โโ
โ โ โ โ โโโโโฌโโโโโ
โ โ โ โ โ โ
โ โผ โผ โผ โผ โ
โ run apple run banana run orange runโ
โ block block block defaultโ
โ โ
โ esac โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: Pattern Types
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Pattern examples โ
โ โ
โ apple โ exact match โ
โ a* โ starts with a โ
โ *e โ ends with e โ
โ ???? โ 4 characters โ
โ [abc] โ a, b, or c โ
โ [a-z] โ lowercase โ
โ [!0-9] โ not a digit โ
โ apple|apricot โ either โ
โ [[:digit:]]* โ starts with digit โ
โ [[:upper:]]* โ starts with uppercase โ
โ *) โ default (catch-all) โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Concept | Syntax | Example |
|---|---|---|
| Basic case | case $x in ... esac | case $fruit in |
| Pattern block | pattern) ... ;; | apple) echo "A" ;; |
| Default | *) | *) echo "Unknown" ;; |
| Alternatives | a|b | apple|apricot) |
| Wildcards | * ? | a*), ????? |
| Char class | [...] | [Oo]range |
| POSIX class | [[:digit:]] | [[:digit:]]*) |
| Negation | [!...] | [!0-9] |
| Fall-through | ;& | a) echo A ;& |
| Continue testing | ;;& | a*) echo ;;& |
Key takeaways:
casematches one value against many patterns โ cleaner than a longif/elifchain- Each block ends with
;; - The whole statement ends with
esac(case backwards) - Use
*as the default to catch unmatched values โ always include it - Patterns support: literal strings, wildcards (
*,?), character classes ([abc],[a-z]), POSIX classes ([[:digit:]]), and alternatives (a|b) - Case is case-sensitive by default โ use
[Aa]ppleor[Yy]for flexibility caseis perfect for: menus, service control, yes/no prompts, file extension dispatch, OS detection, command-line parsing- No fall-through by default โ each match runs its block and stops
- Bash 4+ adds
;∧;&for fall-through and continued testing โ but they’re bash-only - Don’t use
casefor numeric ranges โ that’s forif/[[ ]]or(( ))
Remember: case is the clean way to branch on a single value. Whenever you catch yourself writing if [ "$x" = "a" ] ... elif [ "$x" = "b" ] ... elif ..., reach for case instead. It handles patterns, alternatives, and defaults in a readable, compact form. Always include a *) default to catch the unexpected, and remember that case is case-sensitive โ use character classes to be flexible. Master case, and your dispatch logic becomes clean and obvious.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!