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[@]}

?

+3


source to share


1 answer


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.

+3


source







All Articles