Uso de! na expansão de parâmetros

2

Em link

The basic form of parameter expansion is ${parameter}. ...

If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix} and ${!name[@]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.

...

${!prefix*} ${!prefix@} Expands to the names of variables whose names begin with prefix , separated by the fi rst character of the IFS special variable. When ‘@’ is used and the expan- sion appears within double quotes, each variable name expands to a separate word.

${!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.

Você pode dar alguns exemplos para os parágrafos citados? Eu não tenho ideia do que eles significam.

    
por Tim 05.12.2015 / 19:48

2 respostas

4

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.

    
por 05.12.2015 / 20:16
0

Dê uma olhada na resposta do BinaryZebra para obter uma explicação detalhada. A citação abaixo do TLDP é dita incorreta.

Original:

Analisando o link :

If the first character of "PARAMETER" is an exclamation point, Bash uses the value of the variable formed from the rest of "PARAMETER" as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of "PARAMETER" itself. This is known as indirect expansion.

You are certainly familiar with straight parameter expansion, since it happens all the time, even in the simplest of cases, such as the one above or the following:

franky ~> echo $SHELL
/bin/bash

The following is an example of indirect expansion:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

Note that this is not the same as echo $N*.

Você pode ver os efeitos disso no seu shell.

Exemplo:

$ TEST=(test1 test2 test3)
$ echo ${!TEST*}
TEST
$ echo ${!TEST[@]}
0 1 2
$ echo ${TEST[@]}
test1 test2 test3
$ echo ${#TEST[@]}
4

Observe a diferença entre usar ${!TEST[@]} , ${TEST[@]} e ${#TEST[@]} .

    
por 05.12.2015 / 20:06

Tags