Variable is referenced but not assigned
SC2154 explained: variable is referenced but not assigned. Why the warning fires, how typos silently delete the wrong files, and how to fix it with `set -u`.
Problem
Bash treats unset variables as empty by default, so a typo silently becomes an empty string. `rm -rf "$user_home/.cache"` becomes `rm -rf "/.cache"` if `$user_home` was actually spelled `$userhome`. The script doesn't fail — it deletes the wrong thing.
Bad
dir="$HOMR/projects" # typo: $HOMR
ls "$dir" # silently lists "/projects" or nothingGood
#!/usr/bin/env bash
set -u # fail on unset variables
dir="$HOME/projects"
ls "$dir"
# Or use the safer expansion form to provide a default / fail explicitly:
dir="${HOME:?HOME is unset}/projects"Explanation
`set -u` (or `set -o nounset`) makes Bash exit when you reference an unset variable, surfacing typos immediately. The `${VAR:?message}` form fails per-use without changing global script behavior. Both are dramatically safer than the default.
Related
SC2155
SC2034
When It Matters
A referenced-but-never-assigned variable is either a typo or a dependency on something outside the file. Without set -u it expands to the empty string, so the script continues with a missing value and fails somewhere unrelated — an empty path in a delete, an empty host in a curl, an empty version tag in a release. The warning is most valuable in scripts that read configuration, where a renamed setting leaves references behind that never fail loudly.
Second Example
Note
The ${VAR:=default} form assigns a default in place, while ${VAR:?message} aborts with a clear message — together they document every external input at the top of the script.
Exceptions
Variables set by a sourced config file, exported by a parent process, or assigned indirectly through eval or printf -v are invisible to static analysis. Add a source directive so ShellCheck can follow the file, or disable the rule at the reference with a comment naming the origin.
Faq
Q
What is the difference between SC2154 and SC2153?
A
SC2154 means the variable is never assigned anywhere in the file. SC2153 is the narrower case where a similarly named variable is assigned, suggesting a typo.
Q
How do I declare that a variable comes from the environment?
A
Reference it once with a default or a required check at the top of the script. That both silences the warning and documents the contract.
Q
Does set -u break scripts that use optional variables?
A
It can, which is why optional values should be written as ${VAR:-default} rather than bare references.