Reputation: 80921
Given that the Bash Reference Manual in section 3.5.3 Shell Parameter Expansion
says:
${!name[@]} ${!name[*]}
If name is an array variable, expands to the list of array indices (keys) assigned in name. If name is not an array, expands to 0 if name is set and null otherwise. When ‘@’ is used and the expansion appears within double quotes, each key expands to a separate word.
and
${parameter:-word}
If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.
and
${parameter:+word}
If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.
Can someone explain the output from the following expansions to me:
$ bash --version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
$ cat hm.sh
p() {
printf "%-11s : f=%1s : " "$*" "$f"
eval printf \'%1s :\\n\' "$@"
}
p '$f'
p '${!f[@]}'
p '${!f[@]:-b}'
echo "echo: ${!f[@]:-b} :"
p '${!f[@]:+b}'
echo "echo: ${!f[@]:+b} :"
f=f
p '$f'
p '${!f[@]}'
p '${!f[@]:-b}'
echo "echo: ${!f[@]:-b} :"
p '${!f[@]:+b}'
echo "echo: ${!f[@]:+b} :"
f=t
p '$f'
p '${!f[@]}'
p '${!f[@]:-b}'
echo "echo: ${!f[@]:-b} :"
p '${!f[@]:+b}'
echo "echo: ${!f[@]:+b} :"
$ bash hm.sh
$f : f= : :
${!f[@]} : f= : :
${!f[@]:-b} : f= : b :
echo: b :
${!f[@]:+b} : f= : :
echo: :
$f : f=f : f :
${!f[@]} : f=f : 0 :
${!f[@]:-b} : f=f : f :
echo: f :
${!f[@]:+b} : f=f : b :
echo: b :
$f : f=t : t :
${!f[@]} : f=t : 0 :
${!f[@]:-b} : f=t : b :
echo: b :
${!f[@]:+b} : f=t : :
echo: :
That is why do the contents of the variable in question change how the ${!name[@]:-default}
and ${!name[@]:+alt}
expansions expand when the contents do not change how the ${!name[@]}
expansion itself expands?
Upvotes: 3
Views: 172
Reputation: 241681
In the syntax ${!f[@]}
, the parameter expansion is being parsed as a "list the keys" expression, which is one of the specific exceptions to the rule that {!
introduces a level of indirection. The syntax ${!f[@]:-b}
does not match that pattern (because it ends with :-b
), so the !
is interpreted as an indirect reference, and consequently it is the variable whose name is the value of f
which is being tested by the default value modifier.
The interesting question is, "what does the [@]
modify in that expression?" It seems to be modifying f
, which does nothing when f
is a scalar but produces an invalid name when f
is an array of more than one element; in that case, the default value substitution seems to occur.
My best guess is that this is an undocumented and possibly unintended corner case of parameter expansion.
Upvotes: 3