Prior to
Bash 4.4
set -u
treated empty arrays as "unset", and terminates the process.
There are a number of possible workarounds using array
parameter expansion,
however almost all of them fail in certain Bash versions.
This gist is a supplement to this StackOverflow post.
The only safe option for expanding an array across Bash versions under set -u
is:
${array[@]+"${array[@]}"}
Notice the quotes are inside the expansion, not surrounding the whole expression, and that it uses +
, not :+
.
See results.txt
for a detailed breakdown across several versions of Bash.
Some of these alternatives are "obviously" wrong due to incorrect quoting, but
they're included for completeness.
shorthand | $@ example |
${arr[@]} example |
broken in | notes |
---|---|---|---|---|
":+" | "${@:+"$@"}" |
"${arr[@]:+"${arr[@]}"}" |
4.2+ | |
":+ | "${@:+$@}" |
"${arr[@]:+${arr[@]}}" |
4.2+ | |
"+" | "${@+"$@"}" |
"${arr[@]+"${arr[@]}"}" |
4.2 | |
"+ | "${@+$@}" |
"${arr[@]+${arr[@]}}" |
4.2 | |
:+" | ${@:+"$@"} |
${arr[@]:+"${arr[@]}"} |
* | |
:+ | ${@:+$@} |
${arr[@]:+${arr[@]}} |
* | |
+" | ${@+"$@"} |
${arr[@]+"${arr[@]}"} |
N/A | works in all tested versions (> 3.0) |
+ | ${@+$@} |
${arr[@]+${arr[@]}} |
* | |
":0/1 | "${@:1}" |
"${arr[@]:0}" |
4.2 | crashes, presumably a regression |
:0/1 | ${@:1} |
${arr[@]:0} |
* | also crashes in 4.2 |
":- | "${@:-}" |
"${arr[@]:-}" |
* | |
:- | ${@:-} |
${arr[@]:-} |
* | |
"- | "${@-}" |
"${arr[@]-}" |
* | |
- | ${@-} |
${arr[@]-} |
* |
If we exclude v4.2 several other expansions do work, including
"${@+"$@"}"
and "${@:1}"
, but so long you intend to support that
version these expansions are not safe.
To reproduce the contents of results.txt
run:
for v in 3.1 3.2 4.0 4.1 4.2 4.3 4.4 5.0; do
docker run -v "$PWD:/mnt" "bash:$v" bash /mnt/expansions.sh
done
Bash 3.0 is intentionally excluded from the reported results, but you can run the script against that version too to see what breaks (hint: it's a lot).
If the
eval
-magic feels a bit too handwavy for you, an earlier version of the script doesn't use it.