Tableaux associatifs dans les scripts shell

11

J'ai vu une astuce pour implémenter des tableaux associatifs dans un script shell. Par exemple, print array["apples"]pourrait être scripté comme echo \$array$keyoù clé = pommes.

Cependant, il n'y avait aucune mention de la façon de générer les clés pour itérer sur le tableau. La seule façon dont je pouvais penser était de stocker les clés dans une variable délimitée par des espaces afin que je puisse utiliser une boucle for pour parcourir le tableau.

Alors, existe-t-il un autre moyen de stocker les clés pour une utilisation ultérieure?

Intellectuel
la source
5
Si vous essayez d'utiliser des tableaux associatifs dans un script shell, il est possible que votre projet soit trop complexe pour un script shell :)
Martin von Wittich
@MartinvonWittich pourquoi? J'ai un script shell qui exécute un script SQL sur l'un des 3 schémas DB possibles. Le schéma requis est inclus dans le nom de fichier avec une abréviation. J'ai besoin d'un mappage entre cette abréviation et le vrai nom du schéma. Quoi de mieux qu'un tableau associatif, étant donné que les noms de schéma réels (et non l'abréviation) peuvent différer d'un environnement à l'autre, une variable de tableau (dont les valeurs ne peuvent être définies qu'une seule fois) est parfaite
Slav
2
@Slav Je ne suis pas contre les tableaux associatifs, juste contre les scripts shell où une telle complexité est nécessaire. Mais c'est juste ma préférence personnelle; Je me surprends souvent à commencer à écrire un script shell puis à le réécrire immédiatement en Perl lorsque je me rends compte que je dépasse un certain seuil de complexité.
Martin von Wittich

Réponses:

20

Coques avec tableaux associatifs

Certains shells modernes fournissent des tableaux associatifs: ksh93, bash ≥4, zsh. Dans ksh93 et ​​bash, si aest un tableau associatif, alors "${!a[@]}"est le tableau de ses clés:

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

Dans zsh, cette syntaxe ne fonctionne qu'en mode d'émulation ksh. Sinon, vous devez utiliser la syntaxe native de zsh:

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

${(k)a}fonctionne également si an'a pas de clé vide.

Dans zsh, vous pouvez également faire une boucle sur keys et values ​​en même temps:

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

Coques sans tableaux associatifs

Émuler des tableaux associatifs dans des shells qui n'en ont pas représente beaucoup plus de travail. Si vous avez besoin de tableaux associatifs, il est probablement temps d'apporter un outil plus gros, tel que ksh93 ou Perl.

Si vous avez besoin de tableaux associatifs dans un simple shell POSIX, voici un moyen de les simuler, lorsque les clés sont restreintes pour ne contenir que les caractères 0-9A-Z_a-z(chiffres ASCII, lettres et tiret bas). Dans cette hypothèse, les clés peuvent être utilisées dans le cadre des noms de variables. Les fonctions ci-dessous agissent sur un tableau identifié par un préfixe de dénomination, la «tige», qui ne doit pas contenir deux traits de soulignement consécutifs.

## 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}=\$3
        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"
}

(Avertissement, code non testé. La détection d'erreurs pour les clés et les clés syntaxiquement invalides n'est pas fournie.)

Gilles 'SO- arrête d'être méchant'
la source
5

Je ne sais pas ce que vous entendez par magasin, mais vous pouvez parcourir les clés en utilisant la ${!array[@]}syntaxe:

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

Donc, pour répéter:

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

J'ai trouvé un joli petit tutoriel à ce sujet ici .


Comme indiqué dans les commentaires ci-dessous, des tableaux associatifs ont été ajoutés dans la bashversion 4. Voir ici pour un article de journal Linux sur le sujet.

terdon
la source
1
(bash version 4 only)C'est une chose importante à noter. Traditionnellement, les bashtableaux sont uniquement numériques.
Ricky Beam
1
Vous voudrez peut-être utiliser typesetau lieu de declaredans vos exemples. Cela les rendrait portables entre bash 4 et ksh93 qui ont d'abord implémenté des tableaux associatifs shell.
jlliagre
0

Coques sans tableaux associatifs

Ce n'est pas si difficile lorsque les touches sont restreintes à [0-9A-Za-z_](chiffres, lettres, trait de soulignement).

L'astuce consiste au lieu de stocker dans le tableau [ $ key ], de stocker dans les variables array_ $ key .

Ensemble:

eval "array_$key='$value'"

Avoir:

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

Remarque: Les valeurs ne peuvent pas contenir '(guillemet simple).

Marián Černý
la source
-1

cela fonctionne en 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]}

OU

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

Pas besoin d'utiliser eval afaik

JamesD
la source
1
Je pense que vous avez manqué le point de la question.
G-Man dit `` Réintègre Monica ''