In bash you write `case $answer in y|Y) confirm ;; esac`, leaving the word unquoted. Which expansions does bash apply to that word before matching, and what changes if you quote a pattern instead, as in `"*")`?
answer
- expanded, but never split or globbed
- spaces in the word are harmless here
- patterns get expanded too
- quoted pattern text matches literally
- a quoted star matches only an asterisk
basics
~20 sBash applies tilde, parameter, arithmetic and command-substitution expansion plus quote removal to the case word, but never word splitting or pathname expansion — so an unquoted word is safe even with spaces. Quoting a pattern makes its wildcards literal.
solid answer
~40 sThe word in a `case` is expanded — tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, then quote removal — but it is deliberately **not** word-split and **not** pathname-expanded. That is why `case $file in` cannot blow up on a filename containing spaces the way an unquoted variable does inside `[ ]`; the word stays one word by construction. I still quote it out of habit, because it costs nothing and keeps the rule simple for readers. Patterns are expanded too, which is what lets you build one from a variable — but any *quoted* part of a pattern is matched literally. So `"*")` matches only a literal asterisk, and `"$prefix"*)` treats the variable's content as literal text with a real wildcard after it.
code
bash · 16 lines#!/usr/bin/env bash
file='my report.txt'
case $file in
*.txt) echo "matched, no word splitting: $file" ;;
*) echo "no match" ;;
esac
prefix='a*'
case 'a*b' in
"$prefix"b) echo 'quoted pattern: matched the literal text a*b' ;;
*) echo 'no match' ;;
esac
case 'axb' in
$prefix'b') echo 'unquoted pattern: a* acted as a wildcard' ;;
*) echo 'no match' ;;
esacgo deeper
Know that quoting the word is the safe habit, and that wildcards in a pattern must stay unquoted or they become ordinary characters. Recognise that a quoted star is not a catch-all.
Name the expansions bash applies to the case word and state clearly that word splitting and pathname expansion are not among them, which is why an unquoted word is safe there.
Show the review judgment: spot a pattern built from an unquoted variable, explain who controls the match, and know that a quoted default clause fails silently with no shell error.
Frame it as a trust boundary — decide as a team when input may reach a pattern position at all, and how that rule is enforced in review or lint rather than remembered.
## What bash does to the word When bash reaches `case WORD in`, it expands WORD using tilde expansion, parameter and variable expansion, command substitution and arithmetic expansion, and then performs quote removal. What it pointedly does **not** do is word splitting or pathname expansion. The result is always exactly one word, no matter what it contains. This is a real semantic difference and not a style opinion. In most command positions, an unquoted `$file` holding `my report.txt` becomes two arguments, which is how `[ $file = x ]` ends up with too many arguments and how `for f in $files` silently splits on spaces. In a `case` word that cannot happen: ```bash file='my report.txt' case $file in *.txt) echo "one word, spaces and all: $file" ;; esac ``` The same protection covers globbing: if the variable held `*`, an unquoted use elsewhere might expand to the filenames in the current directory, but as a `case` word it stays the single character `*` and is matched against the patterns as such. ## Should you quote it anyway? Yes, most style guides say `case "$1" in`, and it is a reasonable habit — quoting is free here, it removes the need for the reader to know this special rule, and it survives the code being copied into a context where splitting *does* apply. But when someone tells you the unquoted form is a latent bug, they are wrong about `case` specifically, and knowing exactly which construct protects you is what separates cargo-culted quoting from understood quoting. ## What bash does to each pattern Patterns are expanded too, before they are used for matching. That means a pattern can be built from a variable: ```bash prefix=v case $tag in "$prefix"*) echo "a versioned tag" ;; esac ``` Here the quoted `"$prefix"` contributes literal text and the unquoted `*` after it is a live wildcard. That mix is the whole point of the quoting rule for patterns: **any quoted portion of a pattern is matched as a literal string**, while unquoted metacharacters keep their pattern meaning. Two consequences follow, and both show up in real bugs. First, quoting the default clause breaks it. `"*")` is not a catch-all — it matches one word, the single asterisk character. A block that ends with `"*") echo unknown ;;` will fall through to nothing for every ordinary input, and bash reports no error. Second, an *unquoted* variable in a pattern position brings its own metacharacters to life. If `$prefix` holds `a*`, then `case $tag in $prefix)` matches anything starting with `a`, not the two-character string `a*`. When the variable comes from outside the script, that is a small trust decision: the caller now influences which branch runs. Quote the variable in the pattern when you mean literal text. ```bash prefix='a*' case 'a*b' in "$prefix"b) echo 'quoted: literal a*b matched' ;; esac case 'axb' in $prefix'b') echo 'unquoted: a*b used as a glob' ;; esac ``` Both lines print, for opposite reasons. ## Patterns are never resolved against the filesystem A related confusion: `*.txt` in a pattern position is not turned into the list of `.txt` files in the current directory first. Pathname expansion applies to command arguments, not to the pattern of a `case`. The pattern stays a pattern and is compared with the word, so the block behaves identically in an empty directory and in one full of text files. ## The practical rules 1. Quote the word (`case "$1" in`) for consistency, knowing that bash already protects you there. 2. Never quote a pattern you want to behave as a wildcard — especially not `*)`. 3. Quote the parts of a pattern that must be literal, including variables whose contents you do not control. 4. Remember that a pattern containing an unquoted variable is code, not data: whoever sets the variable decides what matches.
- If the word is never split, why do style guides still insist on `case "$1" in`?Consistency and cheap safety. Quoting costs nothing here, spares the reader from having to know that `case` is a special context, and keeps the code correct if the line is later copied somewhere that does split. It is a habit worth keeping — just do not describe the unquoted form as a bug in a `case`.
- How would you match a word that literally contains a glob character, such as the two characters `a*`?Quote that part of the pattern: `case $tag in "a*") ... ;; esac` matches only the literal two-character string. A backslash escape works the same way. Any quoted portion of a pattern is compared as text, so you can mix a quoted literal with an unquoted wildcard when you need both.
- What is the risk of putting an unquoted, externally supplied variable in a pattern position?Its metacharacters become active, so the caller influences which branch runs — a value of `*` would match every word and steal the dispatch. Treat a pattern built from untrusted input as code rather than data: quote the variable so its contents are matched literally, or validate it before it reaches the pattern.
saying these in an interview costs you the question
- Says an unquoted case word can word-split like in a test command
- Assumes a quoted star pattern still matches anything
- Thinks patterns are literal, so a variable in one is inert
- Believes a pattern is expanded against filenames before matching
- Quotes every pattern by reflex and breaks the wildcards