VMware ESXi and vSphere Cluster Management
Bash case Statement: Multiway Selection in Linux Shell Scripts
Learn Bash case syntax, patterns, default branches, interactive menus, terminators, testing, and troubleshooting with practical Linux shell examples.
What Is a Bash case Statement?
A case statement is a Bash control structure that chooses one command block by matching a single value against multiple patterns. This is called multiway branching because there are more than two possible execution paths.
Use case when one input can have several alternatives, such as menu choices, command options, or response values. It is often clearer than a long chain of if/elif conditions that all test the same variable.
Other programming languages commonly provide a similar construct called a switch statement. Bash calls its version case.
Basic Bash case Syntax
case EXPRESSION in
PATTERN_1)
commands
;;
PATTERN_2)
commands
;;
*)
default commands
;;
esacThe expression is the value Bash evaluates. A branch consists of a pattern followed by a closing parenthesis and the commands that should run when that pattern matches. The normal terminator is ;;. The * pattern is usually the default branch, and esac closes the construct. esac is case spelled backward.
Indent each pattern and its commands consistently. Indentation is not required by Bash, but it makes branches easier to read and maintain.
Parts of a Bash case Statement
How Matching and Execution Work
- Bash evaluates the case expression.
- It compares that value with the branch patterns from top to bottom.
- When the first matching pattern is found, Bash runs that branch's commands.
- The normal
;;terminator ends case processing, so later branches are not checked.
If no explicit pattern matches and there is no * branch, Bash does nothing for the case statement and continues with the command after esac. A default branch is therefore useful when unexpected input must produce a message or another safe action.
Interactive Numbered Menu Example
The following script reads a menu selection and uses case to run one of three Linux commands.
#!/usr/bin/env bash
printf '%s\n' 'Choose an action:'
printf '%s\n' '1) Show the working directory'
printf '%s\n' '2) Show the current date and time'
printf '%s\n' '3) List files in detail'
read -r -p 'Selection: ' CHOICE
case "$CHOICE" in
1)
pwd
;;
2)
date
;;
3)
ls -l
;;
*)
printf 'Invalid selection: %s\n' "$CHOICE"
;;
esacread -r stores the user's input in the descriptive variable CHOICE. Quoting "$CHOICE" makes the expression safe when the value is empty or contains spaces. The patterns 1), 2), and 3) match the valid menu choices. The * branch handles unsupported numbers, text, and empty input.
Menu Input and Result
Patterns and Pattern Alternatives
A case label is a pattern. Patterns can match literal values or use shell glob syntax.
Multiple Alternatives with |
Place several alternatives in one branch with the pipe character. This is useful when several spellings should produce the same result.
read -r -p 'Continue? [y/n] ' ANSWER
case "$ANSWER" in
y|Y|yes|YES)
printf '%s\n' 'Continuing.'
;;
n|N|no|NO)
printf '%s\n' 'Stopping.'
;;
*)
printf '%s\n' 'Please answer yes or no.'
;;
esacCommon Glob Patterns
Character ranges can provide cautious case-insensitive matching, for example [Yy][Ee][Ss] for “yes” in either capitalization. Bash extended patterns can also help with more advanced matching when enabled with shopt -s extglob, but explicit alternatives and character ranges are easier for beginners to audit.
Filename Category Selector
Wildcard patterns are useful for categorizing filenames. Put specific patterns before the catch-all pattern.
read -r -p 'Filename: ' FILE
case "$FILE" in
*.txt)
printf '%s\n' 'This is a text file.'
;;
*.log)
printf '%s\n' 'This is a log file.'
;;
*.sh)
printf '%s\n' 'This is a shell script.'
;;
*)
printf '%s\n' 'Unknown or unsupported file type.'
;;
esacThe pattern *.txt matches a filename ending in .txt. The fallback * should remain last. If it appears first, it can match every value and prevent the specific branches from being reached.
Quoting Expressions and Using Variables
A case expression is commonly a variable expansion such as $CHOICE. Use descriptive names such as CHOICE, ANSWER, or FILE instead of vague names such as x.
case "$CHOICE" in
start)
printf '%s\n' 'Starting.'
;;
stop)
printf '%s\n' 'Stopping.'
;;
esacQuoting the expansion as "$CHOICE" clearly preserves the value when it contains spaces and handles an empty value safely. Bash case matching still compares the resulting value against the patterns.
Branch Terminators
The standard ;; terminator means “finish this branch and stop processing the case statement.” It is the correct choice for ordinary menus and one-result decisions.
Bash also supports advanced continuation terminators:
;&runs the next branch's commands after a match without testing the next pattern.;&&continues testing subsequent patterns and runs the commands of each later matching branch.
These are Bash-specific behaviors and can cause commands from an unexpected branch to run if used accidentally. Prefer ;; unless continuation is intentional.
case Versus if/elif
Save, Check, and Run a Script
Save the menu example in a file named menu.sh. The shebang #!/usr/bin/env bash asks the environment to locate Bash.
bash -n menu.sh
chmod +x menu.sh
./menu.sh
bash menu.shbash -n menu.sh checks syntax without running the script. chmod +x menu.sh adds execute permission, allowing ./menu.sh. Running bash menu.sh invokes Bash explicitly and does not require the executable permission bit.
If installed, shellcheck menu.sh can identify common shell scripting issues in addition to syntax checking.
Testing Checklist
- Enter
1and confirm that the working directory is printed. - Enter
2and confirm that the date and time are printed. - Enter
3and confirm that a detailed listing appears. - Enter an unsupported number and confirm that the default message appears.
- Enter non-numeric text and press Enter on an empty input to test fallback handling.
Troubleshooting
Every Input Reaches the Invalid Branch
Check that the patterns match the actual input, that the same variable is used by read and case, and that unexpected whitespace or characters are not present. During debugging, print the captured value with a command such as printf '<%s>\n' "$CHOICE". Make sure intended patterns appear before *.
Syntax Error Near esac
A branch may be missing its closing parenthesis, its ;;, the in keyword, or the closing esac. Compare the script with the canonical layout and run bash -n menu.sh.
A Specific Branch Never Runs
The catch-all * branch or another broad wildcard may appear before the intended branch. Move specific patterns earlier and place * last. Also check capitalization and add accepted alternatives such as y|Y when needed.
Unexpected Commands Also Execute
Look for accidental use of ;& or ;&&. Replace the continuation terminator with ;; for normal one-branch behavior.
The Script Fails When Run Directly
Run chmod +x menu.sh and verify that the first line contains a valid Bash shebang. Alternatively, run the file explicitly with bash menu.sh.
Summary
caseselects among multiple branches by matching one expression against shell patterns.- Each branch has a pattern, commands, and normally ends with
;;. - The
*branch provides a fallback and usually belongs last. - Use
|, glob patterns, wildcards, and bracket expressions to describe accepted values. - Quote variable expressions such as
"$CHOICE", validate input, and check syntax withbash -n. - Prefer
casefor menus and many alternatives for one value; preferiffor general tests and comparisons.
Continue with the Bash case statement lesson when you need a quick reference for this construct.