Precisamos comparar (e distinguir entre):
"${Var}" # Plain variable
"${!Var}" # Indirect expansion
"${!Var@}" # Prefix expansion
"${!Var[@]}" # Array keys expansion
"${Var[@]}" # Plain array expansion
Há também as expansões de *
que são muito semelhantes, mas têm uma pequena diferença.
Indirection
Exemplo de indireção:
$ varname=var_one
$ var_one=a-value
$ echo "${varname}"
var_one
$ echo "${!varname} and ${var_one}"
a-value and a-value
Prefixo
Exemplo de prefixo:
$ head_one=foo
$ head_two=bar
$ printf '<%s> ' "${!head@}"
<head_one> <head_two>
$ printf '<%s> ' "${!head*}"
<head_one head_two>
Note que as variáveis são coladas pelo primeiro caractere do IFS, que por padrão é um espaço (como o IFS é Espaço Tab NewLine por padrão).
Matriz simples
Exemplo de Array (não! usado) para mostrar a pequena (mas importante) diferença de @
e *
:
$ Array[1]=This
$ Array[2]=is
$ Array[3]=a
$ Array[4]=simple
$ Array[5]=test.
$ printf '<%s> ' "${Array[@]}"
<This> <is> <a> <simple> <test.>
$ printf '<%s> ' "${Array[*]}"
<This is a simple test.>
O mesmo comentário sobre o IFS se aplica aqui.
Note que eu não atribuí o índice 0 (propositalmente) do Array.
Note que uma maneira mais simples de atribuir o Array é:
$ Array=( "" This is a simple test.)
Mas aqui o índice 0 deve ser usado, e eu usei um valor vazio (que não é o mesmo que um valor não definido como acima).
Array LIST
Para isso, um simples array indexado (com números) não é tão divertido:
$ Array=( "" A simple example of an array.)
$ printf '<%s> ' "${!Array[@]}"
<0> <1> <2> <3> <4> <5> <6>
$ printf '<%s> ' "${!Array[*]}"
<0 1 2 3 4 5 6>
Mas para um array associativo, as coisas se tornam mais interessantes
$ unset Array # erase any notion of variable array.
$ declare -A Array # make it associative
$ Array=([foo]=one [bar]=two [baz]=three) # give it values.
$ printf '<%s> ' "${Array[@]}"
<two> <three> <one> # List of values.
$ printf '<%s> ' "${!Array[@]}"
<bar> <baz> <foo> # List of keys
$ printf '<%s> ' "${Array[*]}"
<two three one> # One string of list of values.
$ printf '<%s> ' "${!Array[*]}"
<bar baz foo> # One string of list of keys.
Por favor, note que o pedido não é o mesmo de quando atribuído.
Nota: Todos os usos que apresentei são citados "${!Array[@]}"
, os valores não cotados ${!Array[@]}
e ${!Array[*]}
funcionam exatamente iguais, fornecem a mesma saída (no Bash).
Mas são afetados pela divisão do shell no valor IFS. E a feia, sempre problemática "expansão do Pathname". Não é tão útil em geral. Ou para ser usado com muito cuidado, em qualquer caso.