O valor recuperado da matriz associativa está errado?

1

Eu tenho passado pelo livro "Bash Pocket Reference" e cheguei à seção sobre matrizes associativas. Agora, tentar o código de exemplo no livro me dá respostas inesperadas:

istanev@inspiron5559:~$ data=([joe]=30 [mary]=25)
istanev@inspiron5559:~$ echo ${data[joe]}
25
istanev@inspiron5559:~$ echo ${data[mary]}
25

Os dados [joe] não devem retornar 30? Por que ele está retornando 25 em vez disso? Minha versão bash é 4.3.46 (1) -release.

    
por Ivan Stanev 03.12.2016 / 17:56

2 respostas

2

Por padrão matrizes de processo bash como matrizes indexadas.
Nesse caso, os índices são avaliados como uma expressão aritmética.

$ joe=3    mary=6
$ unset data
$ data=([joe]=111 [mary]=bbb)
$ declare -p data
declare -a data=([3]="111" [6]="bbb")

A saída revela várias coisas:

  • A matriz é indexada: o -a na saída.
  • A matriz contém dois valores.
  • Os índices dos valores correspondem aos valores numéricos das variáveis joe e mary .
  • Os valores contidos na matriz podem ser strings.

Isso acontece mesmo que os índices sejam citados (até mesmo aspas simples):

$ joe=3    mary=6
$ unset data
$ data=(["joe"]=111 ["mary"]=bbb)
$ declare -p data
declare -a data=([3]="111" [6]="bbb") 

Se as strings usadas como índices não foram definidas para conter um número, são de qualquer maneira avaliadas como uma Expressão Aritmética que possui valor zero.

$ unset joe    ;    unset mary    ;    unset data
$ data=([joe]=111 [mary]=bbb)
$ declare -p data
declare -a data=([0]="bbb")

O que aconteceu é que [joe]=111 avaliou para [0]=111 , definindo a matriz no índice 0 para 111 . Porém, [mary]=bbb avaliou para [0]=bbb , substituindo assim o valor da matriz no índice 0 para bbb .

Para realmente ter um array Associativo, ele deve ser definido antes de seu uso.
Não pode ser alterado enquanto contém dados. Com o array definido como acima:

$ declare -A data
bash: declare: data: cannot convert indexed to associative array

Mas, limpando, podemos:

$ joe=3  ;  mary=6  ; unset data

$ declare -A data

$ data=([joe]=111 [mary]=bbb)
$ declare -p data
declare -A data=([joe]="111" [mary]="bbb" )

Como você pode ver, não importa que as strings usadas como índices também sejam nomes de variáveis válidos e que elas contenham um valor. Eles são usados como índices de string para o array associativo.

    
por 04.12.2016 / 03:32
2

Matrizes associativas precisam ser declaradas explicitamente, com typeset -A ou algo equivalente ( declare -A ou readonly -A no bash). Por padrão, uma matriz é uma matriz “simples”, com índices inteiros. Índices não numéricos em matrizes indexadas por inteiros são interpretados como expressões aritméticas, e nomes de variáveis não definidos em expressões aritméticas são interpretados silenciosamente como 0, então data=([joe]=30 [mary]=25) conjuntos data[0]=30 , então data[0]=25 e ${data[whatever]} é elemento 0 que é 25 .

bash-4.3$ indexed=([a]=aye [b]=bee [x+1]=cee)
bash-4.3$ echo length=${#indexed[@]} a=${indexed[a]} b=${indexed[b]} x+1=${indexed[x+1]} 1=${indexed[1]}
length=2 a=bee b=bee x+1=cee 1=cee
bash-4.3$ typeset -A associative=([a]=aye [b]=bee [x+1]=cee)
bash-4.3$ echo length=${#associative[@]} a=${associative[a]} b=${associative[b]} x+1=${associative[x+1]} 1=${associative[1]}
length=3 a=aye b=bee x+1=cee 1=

Como indexed é uma matriz com índices numéricos, indexed[a] e indexed[b] são ambos indexed[0] e indexed[x+1] é indexed[1] . Com uma matriz associativa, o que está dentro do parêntese é analisado como uma string (com as expansões usuais, como nas aspas duplas, para que você possa escrever ${associative[$key]} ).

    
por 04.12.2016 / 00:16