In bash < 4.4
"${a[@]}"
fails (unbound variable) if a
is unset (nothing was assigned to a
) or a=()
. Also "${a[@]:+${a[@]}}"
and "${a[@]+${a[@]}}"
produce empty arrays if a=('')
.
What works before, after and in 4.4
is ${a[*]+"${a[@]}"}
and ${a[@]+"${a[@]}"}
.
It should also be mentioned that ${#a[@]}
fails if a
is unset (regardless of the version). And ${a[i]}
fails if the specified element doesn't exist.
a.bats
:
setup() {
[ "$BATS_LIB_PATH" = /usr/lib/bats ] && BATS_LIB_PATH=$HOME/.bats/lib:$BATS_LIB_PATH
bats_load_library bats-support
bats_load_library bats-assert
bats_require_minimum_version 1.5.0
set -u
}
function args2str { local IFS=\|; echo "$#:($*)"; }
version_gte() {
[ "`printf '%s\n%s\n' "$1" "$2" | sort -V | head -1`" != "$1" ]
}
bash_version() {
echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}"
}
bash_gte() { version_gte "`bash_version`" "$1"; }
bash_lt() { ! version_gte "`bash_version`" "$1"; }
# "${a[@]}"
@test "\"\${a[@]}\" fails if a is unset (unbound variable)" {
bash_gte 4.4 && skip
run -127 bash -uc ': ${a[@]}'
assert_output --partial 'unbound variable'
}
@test "\"\${a[@]}\" produces 0:() if a is unset" {
bash_lt 4.4 && skip
assert_equal "`args2str "${a[@]}"`" "0:()"
}
@test "\"\${a[@]}\" fails if a=() (unbound variable)" {
bash_gte 4.4 && skip
run -127 bash -uc 'a=(); : ${a[@]}'
assert_output --partial 'unbound variable'
}
@test "\"\${a[@]}\" produces 0:() if a=()" {
bash_lt 4.4 && skip
a=()
assert_equal "`args2str "${a[@]}"`" "0:()"
}
# "${a[@]:+${a[@]}}"
@test "\"\${a[@]:+\${a[@]}}\" produces 0:() if a=('')" {
bash_gte 4.4 && skip
a=('')
assert_equal "`args2str "${a[@]:+${a[@]}}"`" "0:()"
}
@test "\"\${a[@]:+\${a[@]}}\" produces 1:() if a=('')" {
bash_lt 4.4 && skip
a=('')
assert_equal "`args2str "${a[@]:+${a[@]}}"`" "1:()"
}
# "${a[@]+${a[@]}}"
@test "\"\${a[@]+\${a[@]}}\" produces 0:() if a=('')" {
bash_gte 4.4 && skip
a=('')
assert_equal "`args2str "${a[@]+${a[@]}}"`" "0:()"
}
@test "\"\${a[@]+\${a[@]}}\" produces 1:() if a=('')" {
bash_lt 4.4 && skip
a=('')
assert_equal "`args2str "${a[@]+${a[@]}}"`" "1:()"
}
# ${a[*]:+"${a[@]}"}
@test "\${a[*]:+\"\${a[@]}\"} produces 0:() if a=('')" {
a=('')
assert_equal "`args2str ${a[*]:+"${a[@]}"}`" "0:()"
}
# ${a[@]:+"${a[@]}"}
@test "\${a[@]:+\"\${a[@]}\"} produces 0:() if a=('')" {
a=('')
assert_equal "`args2str ${a[@]:+"${a[@]}"}`" "0:()"
}
# ${a[*]+"${a[@]}"}
@test "\${a[*]+\"\${a[@]}\"} produces 0:() if a is unset" {
assert_equal "`args2str ${a[*]+"${a[@]}"}`" "0:()"
}
@test "\${a[*]+\"\${a[@]}\"} produces 0:() if a=()" {
a=()
assert_equal "`args2str ${a[*]+"${a[@]}"}`" "0:()"
}
@test "\${a[*]+\"\${a[@]}\"} produces 1:() if a=('')" {
a=('')
assert_equal "`args2str ${a[*]+"${a[@]}"}`" "1:()"
}
@test "\${a[*]+\"\${a[@]}\"} produces 1:(a) if a=(a)" {
a=(a)
assert_equal "`args2str ${a[*]+"${a[@]}"}`" "1:(a)"
}
@test "\${a[*]+\"\${a[@]}\"} produces 2:(a|b) if a=(a b)" {
a=(a b)
assert_equal "`args2str ${a[*]+"${a[@]}"}`" "2:(a|b)"
}
# ${a[@]+"${a[@]}"}
@test "\${a[@]+\"\${a[@]}\"} produces 0:() if a is unset" {
assert_equal "`args2str ${a[@]+"${a[@]}"}`" "0:()"
}
@test "\${a[@]+\"\${a[@]}\"} produces 0:() if a=()" {
a=()
assert_equal "`args2str ${a[@]+"${a[@]}"}`" "0:()"
}
@test "\${a[@]+\"\${a[@]}\"} produces 1:() if a=('')" {
a=('')
assert_equal "`args2str ${a[@]+"${a[@]}"}`" "1:()"
}
@test "\${a[@]+\"\${a[@]}\"} produces 1:(a) if a=(a)" {
a=(a)
assert_equal "`args2str ${a[@]+"${a[@]}"}`" "1:(a)"
}
@test "\${a[@]+\"\${a[@]}\"} produces 2:(a|b) if a=(a b)" {
a=(a b)
assert_equal "`args2str ${a[@]+"${a[@]}"}`" "2:(a|b)"
}
# ${#a[@]}
@test "\${#a[@]} fails if a is unset (unbound variable)" {
run -1 bash -uc ': ${#a[@]}'
assert_output --partial 'unbound variable'
}
# ${a[0]}
@test "\${a[0]} fails if a is unset (unbound variable)" {
run -127 bash -uc ': ${a[0]}'
assert_output --partial 'unbound variable'
}
@test "\${a[0]} fails if a=() (unbound variable)" {
run -127 bash -uc 'a=(); : ${a[0]}'
assert_output --partial 'unbound variable'
}
$ git clone https://github.com/bats-core/bats-core ~/.bats
$ git clone https://github.com/bats-core/bats-support ~/.bats/lib/bats-support
$ git clone https://github.com/bats-core/bats-assert ~/.bats/lib/bats-assert
$ ~/.bats/bin/bats a.bats