case
| Since: | 基本構文(;; / *) | POSIX(sh互換) |
|---|---|---|
| ;& ;;& (fallthrough) | Bash(bash拡張) |
The case statement in shell scripts matches the value of a variable or string against patterns and branches execution accordingly. The same branching can be done with if-elif-else, but when there are many branches, case is far more readable. A case block is closed with esac (the word "case" reversed). Each pattern ends with ), and ;; is placed at the end of the processing block to explicitly signal that execution does not fall through to the next pattern.
Basic Syntax
A case statement lists patterns after the in keyword and is closed with esac.
| Element | Meaning | Description |
|---|---|---|
case value in | Begin matching | Matches the value against patterns. Variables, command substitutions, and string literals can be used. |
pattern) | Pattern definition | Specifies the pattern to match. Glob notation is available. |
;; | End block, do not fall through | Finishes processing this pattern and exits the entire case statement. |
;;& | End block, continue evaluating (bash 4.0+) | After processing this pattern, continues evaluating subsequent patterns. Executes any that match. |
;& | End block, unconditionally execute next (bash 4.0+) | After processing this pattern, unconditionally executes the next pattern's processing without evaluation (equivalent to C's fallthrough). |
*) | Default (wildcard) | Executed when no other pattern matches. |
esac | Terminator | Closes the case block. |
# Basic case statement structure
case value in
pattern1)
# Executed when pattern1 matches
processing_A
;;
pattern2)
# Executed when pattern2 matches
processing_B
;;
*)
# Executed when no pattern matches
default_processing
;;
esac
Writing Patterns
Patterns support glob notation and multiple alternatives with |. Note that regular expressions cannot be used.
| Pattern | Meaning | Description |
|---|---|---|
string | Exact match | Matches when the value exactly equals the specified string. |
* | Any string (0 or more characters) | Matches anything. Used for the default case. |
? | Any single character | Matches any single character. Used to match by character count. |
[abc] | Character class | Matches any one of the characters inside the brackets. |
[a-z] | Character range | Matches any single character within the specified range. |
patternA|patternB | OR (multiple patterns) | Executes when either pattern matches. Used to apply the same processing to multiple values. |
Difference Between ;; and ;;&
The type of terminator (the symbol at the end of a pattern block) determines behavior after a match. ;;& and ;& are only available in bash 4.0 and later.
| Terminator | Behavior | Description |
|---|---|---|
;; | Immediate exit | After executing this pattern's processing, exits the entire case statement. The most common form. |
;;& | Continue evaluating next patterns | After executing this pattern's processing, continues evaluating the remaining patterns from the top. Executes any that match. |
;& | Unconditionally execute next | After executing this pattern's processing, unconditionally executes the next pattern's processing without evaluation (same behavior as C's fallthrough). |
Sample Code
eva_case_basic.sh
#!/bin/bash
# -----------------------------------------------
# Branch on Evangelion pilots using a case statement
# (basic exact match example using ;;)
# -----------------------------------------------
# Set the pilot name to evaluate
pilot="Soryu Asuka"
echo "=== Pilot identification ==="
echo "Target: ${pilot}"
echo ""
case "$pilot" in
"Ikari Shinji")
# Unit-01 pilot
echo "Unit: Evangelion Unit-01 (backup pilot for Unit-00)"
echo "Unit number: Unit-01"
;;
"Ayanami Rei")
# Unit-00 pilot
echo "Unit: Evangelion Unit-00"
echo "Unit number: Unit-00"
;;
"Soryu Asuka")
# Unit-02 pilot
echo "Unit: Evangelion Unit-02"
echo "Unit number: Unit-02"
;;
"Nagisa Kaworu")
# 17th Angel / 5th candidate
echo "Unit: Evangelion Unit-03 (provisional)"
echo "Unit number: Unit-02 (including Unit-13)"
;;
"Makinami Mari")
# Provisional Unit-05 / Unit-02' pilot
echo "Unit: Evangelion Provisional Unit-05 / Unit-02'"
echo "Unit number: Unit-05 / Unit-02'"
;;
*)
# Pilot not in the registry
echo "${pilot} is not registered in the pilot roster."
;;
esac
chmod +x eva_case_basic.sh ./eva_case_basic.sh === Pilot identification === Target: Soryu Asuka Unit: Evangelion Unit-02 Unit number: Unit-02
eva_case_pattern.sh
#!/bin/bash
# -----------------------------------------------
# Example using wildcards, ?, and | for pattern matching
# Classifies Angel battle records (codenames) by pilot
# -----------------------------------------------
# Receive a status code from a command-line argument
# Default to "A-001" if no argument is given
code="${1:-A-001}"
echo "=== Angel battle code classification: ${code} ==="
echo ""
case "$code" in
A-???)
# Matches "A-" followed by any 3 characters (Angel battles 1-999)
echo "Classification: Angel engagement record (Ikari Shinji / Ayanami Rei / Soryu Asuka)"
;;
E-001|E-002|E-003)
# Use | to specify multiple values with OR
# E-001: Ikari Shinji, E-002: Ayanami Rei, E-003: Soryu Asuka sortie records
echo "Classification: Initial pilot sortie record (Shinji / Rei / Asuka)"
;;
E-004|E-005)
# E-004: Nagisa Kaworu, E-005: Makinami Mari sortie records
echo "Classification: Additional pilot sortie record (Kaworu / Mari)"
;;
M-[0-9][0-9][0-9])
# Matches "M-" followed by exactly 3 digits (operation codes)
echo "Classification: NERV operation record"
;;
[a-z]*)
# Codes starting with a lowercase letter are treated as unofficial logs
echo "Classification: Unofficial log (codes starting with lowercase are unauthenticated)"
;;
*)
# Does not match any of the above
echo "Classification: Unknown code (check with MAGI system)"
;;
esac
chmod +x eva_case_pattern.sh # Matches A-??? ./eva_case_pattern.sh A-003 === Angel battle code classification: A-003 === Classification: Angel engagement record (Ikari Shinji / Ayanami Rei / Soryu Asuka) # Matches the | multi-pattern ./eva_case_pattern.sh E-002 === Angel battle code classification: E-002 === Classification: Initial pilot sortie record (Shinji / Rei / Asuka) # Matches [0-9][0-9][0-9] ./eva_case_pattern.sh M-007 === Angel battle code classification: M-007 === Classification: NERV operation record # Matches default (*) ./eva_case_pattern.sh X-99 === Angel battle code classification: X-99 === Classification: Unknown code (check with MAGI system)
eva_case_fallthrough.sh
#!/bin/bash
# -----------------------------------------------
# Comparing ;; and ;;&
# (requires bash 4.0 or later)
# Classifying pilots by suitability rank with tags
# -----------------------------------------------
# Set the pilot name to evaluate
pilot="Ikari Shinji"
echo "=== Using ;; (exit immediately on match) ==="
echo "Target: ${pilot}"
echo ""
# With ;; only the first matching pattern executes, then the case exits
case "$pilot" in
"Ikari Shinji"|"Ayanami Rei"|"Soryu Asuka")
echo "[tag] Initial pilot"
;;
"Ikari Shinji"|"Nagisa Kaworu")
# With ;; the case exits after the first match
# This block can never be reached
echo "[tag] Soul lineage"
;;
*)
echo "[tag] Other"
;;
esac
echo ""
echo "=== Using ;;& (continue evaluating after match) ==="
echo "Target: ${pilot}"
echo ""
# With ;;& evaluation continues over remaining patterns after a match
# Used to assign multiple tags when a value matches multiple patterns
case "$pilot" in
"Ikari Shinji"|"Ayanami Rei"|"Soryu Asuka")
echo "[tag] Initial pilot"
;;& # <- continue evaluating next patterns even after a match
"Ikari Shinji"|"Nagisa Kaworu")
echo "[tag] Soul lineage"
;;& # <- continue evaluating
"Makinami Mari"|"Ikari Shinji")
echo "[tag] Main pilot (theatrical)"
;;&
*)
# * always matches, so a common tag is added for everyone
echo "[tag] NERV registered"
;;
esac
chmod +x eva_case_fallthrough.sh ./eva_case_fallthrough.sh === Using ;; (exit immediately on match) === Target: Ikari Shinji [tag] Initial pilot === Using ;;& (continue evaluating after match) === Target: Ikari Shinji [tag] Initial pilot [tag] Soul lineage [tag] Main pilot (theatrical) [tag] NERV registered
When to Use case vs if
| Aspect | case statement | if statement |
|---|---|---|
| Best suited for | Matching a single variable against multiple values or patterns. | Conditions combining multiple variables or numeric comparisons. |
| Pattern matching | Glob notation (*, ?, [abc]) is available. | Globs and regular expressions (=~) are available inside [[ ]]. |
| Numeric comparison | Not available (string matching only). | Numeric comparisons are available with -eq, -lt, -gt, etc. |
| Readability | Cleaner when there are many branches. | Better suited when there are few branches but complex conditions. |
| POSIX compliance | POSIX-compliant with ;; only. ;;& and ;& require bash 4.0+. | POSIX-compliant when using [ ]. |
Notes
The case statement in shell scripts matches a single variable or command output against multiple patterns and branches execution. The block is closed with esac, and each pattern ends with ). Glob notation (*, ?, [abc]) is available in patterns, and multiple patterns can be combined with | as an OR condition. The terminator at the end of each block is normally ;; (immediate exit), but bash 4.0+ also supports ;;& (continue evaluating after match) and ;& (unconditionally execute next). When conditions combine multiple variables or require numeric comparisons, use if statements. See also [ ] and [[ ]] for details on conditional expressions.
If you find any errors or copyright issues, please contact us.