Bash Debugging Pitfalls
Debugging pitfalls are small habits that hide bugs instead of exposing them. Each one below prints a surprising result, and each fix is short.
Unquoted words split, quoted words stay whole
The unquoted loop sees three separate words. The quoted loop keeps the whole phrase as one item.
data="red green blue"
for item in $data; do echo "item: $item"; done
for item in "$data"; do echo "kept: $item"; doneAn unquoted star matches file names
Two text files are made first, so the star has files to match. The unquoted echo lists the files, while the quoted echo prints the star itself.
touch a.txt b.txt
pattern="*.txt"
echo $pattern
echo "$pattern"An empty variable breaks an unquoted test
The variable holds an empty string. The unquoted test prints an error to stderr, and the script exits with status 2.
name=""
[ $name = "yes" ]set -u fails on an unset variable
The variable missing is never set. Reading it under set -u prints an error and stops the script with status 1.
set -u
echo "$missing"Example
set -u
name=""
phrase="red green"
if [ "$name" = "yes" ]; then
echo "name is yes"
else
echo "name is not yes"
fi
for item in "$phrase"; do echo "kept: $item"; done
echo "missing is ${missing:-none}"Key points
- Word splitting: unquoted expansion breaks one value into many words.
- Glob expansion: an unquoted star in a value can match file names.
- Quoting: double quotes keep one value as one word.
- Empty test trap: an unquoted empty variable breaks a [ test.
- set -u: a switch that fails on an unset variable.
- Default value: ${var:-word} gives a safe value when var is unset.
In this example, set -u is on, so every variable read must be safe. The test quotes the empty name, so it compares cleanly instead of breaking. The loop quotes the phrase, so it stays one item. The last line uses a default, so the unset variable prints none instead of failing.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Under set -u, what does ${missing:-none} print when missing is unset?