Matrizes Associativas em Scripts Shell

10

Eu vi um truque para implementar matrizes associativas em um script de shell. Por exemplo, print array["apples"] pode ser roteirizado como echo \$array$key , em que key = apples.

No entanto, não houve menção de como gerar as chaves para iterar no array. A única maneira que eu conseguia pensar era armazenar as chaves em uma variável delimitada por espaços para que eu pudesse usar um loop para iterar sobre a matriz.

Então, existe alguma outra maneira de armazenar as chaves para uso posterior?

    
por EggHead 28.01.2014 / 23:35

4 respostas

19

Shells com matrizes associativas

Algumas shells modernas fornecem matrizes associativas: ksh93, bash ≥4, zsh. Em ksh93 e bash, se a for uma matriz associativa, então "${!a[@]}" é a matriz de suas chaves:

for k in "${!a[@]}"; do
  echo "$k -> ${a[$k]}"
done

No zsh, essa sintaxe só funciona no modo de emulação ksh. Caso contrário, você terá que usar a sintaxe nativa do zsh:

for k in "${(@k)a}"; do
  echo "$k -> $a[$k]"
done

${(k)a} também funciona se a não tiver uma chave vazia.

No zsh, você também pode executar o loop nos dois k eys e v alues ao mesmo tempo:

for k v ("${(@kv)a}") echo "$k -> $v"

Conchas sem matrizes associativas

Emular matrizes associativas em shells que não as têm é muito mais trabalhoso. Se você precisa de matrizes associativas, provavelmente é hora de trazer uma ferramenta maior, como ksh93 ou Perl.

Se você precisa de matrizes associativas em um simples shell POSIX, aqui está uma maneira de simulá-las, quando as chaves são restritas para conter apenas os caracteres 0-9A-Z_a-z (dígitos ASCII, letras e sublinhados). Sob esta suposição, as chaves podem ser usadas como parte dos nomes das variáveis. As funções abaixo atuam em uma matriz identificada por um prefixo de nomenclatura, o "radical", que não deve conter dois sublinhados consecutivos.

## ainit STEM
## Declare an empty associative array named STEM.
ainit () {
  eval "__aa__${1}=' '"
}
## akeys STEM
## List the keys in the associatve array named STEM.
akeys () {
  eval "echo \"\$__aa__${1}\""
}
## aget STEM KEY VAR
## Set VAR to the value of KEY in the associative array named STEM.
## If KEY is not present, unset VAR.
aget () {
  eval "unset $3
        case \$__aa__${1} in
          *\" $2 \"*) $3=\$__aa__${1}__$2;;
        esac"
}
## aset STEM KEY VALUE
## Set KEY to VALUE in the associative array named STEM.
aset () {
  eval "__aa__${1}__${2}=\
        case \$__aa__${1} in
          *\" $2 \"*) :;;
          *) __aa__${1}=\"\${__aa__${1}}$2 \";;
        esac"
}
## aunset STEM KEY
## Remove KEY from the associative array named STEM.
aunset () {
  eval "unset __aa__${1}__${2}
        case \$__aa__${1} in
          *\" $2 \"*) __aa__${1}=\"\${__aa__${1}%%* $2 } \${__aa__${1}#* $2 }\";;
        esac"
}

(Aviso, código não testado. Detecção de erro para hastes e chaves sintaticamente inválidas não é fornecida.)

    
por 29.01.2014 / 01:48
5

Não tenho certeza do que você quer dizer com loja, mas é possível percorrer as chaves usando a sintaxe ${!array[@]} :

$ typeset -A foo=([key1]=bar [key2]=baz);
$ echo "${!foo[@]}" 
key2 key1

Então, para iterar:

$ for key in "${!foo[@]}"; do echo "$key : ${foo[$key]}"; done
key2 : baz
key1 : bar

Eu encontrei um tutorial interessante sobre este aqui .

Como apontado nos comentários abaixo, matrizes associativas foram adicionadas em bash versão 4. Veja aqui para um artigo de jornal do Linux sobre o assunto.

    
por 28.01.2014 / 23:58
0

Conchas sem matrizes associativas

Não é tão difícil quando as chaves estão restritas a [0-9A-Za-z_] (números, letras, sublinhado).

O truque é, em vez de armazenar no array [<> $ key ], armazenar nas variáveis array_ $ key .

Definir:

eval "array_$key='$value'"

Obtenha:

value='eval echo '$'array_$key'

Observação: os valores não podem conter ' (aspas simples).

    
por 06.01.2017 / 04:50
-1

isso funciona no bash

cert="first"
web="second"
declare -A assoc_array=(["cert"]="${cert}" ["web"]="${web}")
echo "first is" ${assoc_array[cert]}
echo "second is" ${assoc_array[web]}

OR

#loop
for i in "${assoc_array[@]}"
do
   echo "$i"
done

Não há necessidade de usar eval afaik

    
por 14.03.2019 / 01:10