Bash non-array $ {! name [@]} parameter expansion confusion
Considering the Bash Reference Manual in the section 3.5.3 Shell Parameter Expansion
says:
${!name[@]} ${!name[*]}
If name is an array variable, it expands to a list of array indices (keys), assigned by name. If the name is not an array, it is incremented to 0 if the name is given, and null otherwise. When "@" is used and the extension appears in double quotes, each key is expanded to a separate word.
and
$ {parameter: -word}
If the parameter is not specified or null, the word is replaced. Otherwise, the parameter value will be overwritten.
and
$ {parameter: + word}
If the parameter is null or unset, nothing is replaced, otherwise the word is replaced.
Can someone explain the output from the following extensions 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: :
This is why the content of the variable in question changes how the extensions are expanded ${!name[@]:-default}
and ${!name[@]:+alt}
when the content doesn't change how the extension is expanded ${!name[@]}
?
source to share
In the syntax, ${!f[@]}
parameter expansion is parsed as "list the keys", which is one of the special exceptions to the rule that {!
introduces a level of indirection. The syntax ${!f[@]:-b}
does not follow this pattern (because it ends with :-b
), so it is !
interpreted as an indirect reference, and hence it is a variable whose name is the value f
that is checked by the default value modifier.
An interesting question: "What will change [@]
in this expression?" It seems to modify f
, which does nothing when it f
is a scalar, but creates an invalid name when f
is an array of more than one element; in this case, the default replacement appears.
My best guess is that this is an undocumented and possibly unintentional corner case of parameter expansion.
source to share