web-dev-qa-db-fra.com

Les tableaux associatifs sont locaux par défaut

Les tableaux associatifs semblent être locaux par défaut lorsqu'ils sont déclarés dans un corps de fonction, où ils devraient être globaux. Le code suivant

#!/bin/bash

f() {
    declare -A map
    map[x]=a
    map[y]=b
}

f
echo x: ${map[x]} y: ${map[y]}

produit la sortie:

x:  y:

alors que ce

#!/bin/bash

declare -A map

f() {
    map[x]=a
    map[y]=b
}

f
echo x: ${map[x]} y: ${map[y]}

produit la sortie:

x: a y: b

Est-il possible de déclarer un tableau associatif global au sein d'une fonction? Ou quelle solution de contournement peut être utilisée?

25
davide

De: Greg Wooledge
Envoyé: mar, 23 août 2011 06:53:27 -0700
Objet: Re: YAQAGV (Encore une question sur les variables globales)

bash 4.2 ajoute "declare -g" pour créer des variables globales à partir d'une fonction .

Merci Greg! Cependant, Squeeze Debian a toujours Bash 4.1.5

19
davide

Vous avez déjà répondu à votre propre question avec declare -g. La solution de contournement sur les versions de bash <4.2 consiste à déclarer le tableau en dehors de la fonction.

f() {
   map[y] = foo
}

declare -A map
foo
echo "${map[y]}"
6
jordanm

Très bien, 4.2 ajoute "declare -g" mais c'est un buggy pour les tableaux associatifs, donc il ne répond pas (encore) à la question. Voici mon rapport de bogue et la confirmation de Chet qu'un correctif est prévu pour la prochaine version.

http://lists.gnu.org/archive/html/bug-bash/2013-09/msg00025.html

Mais j'ai trouvé par hasard une solution de contournement, au lieu de déclarer le tableau et de lui affecter une valeur initiale en même temps, commencez par déclarer le tableau, puis effectuez l'affectation. C'est-à-dire, ne faites pas ceci:

declare -gA a=([x]=1 [y]=2)

mais ceci à la place:

declare -gA a; a=([x]=1 [y]=2)
5
memeplex

Pour ceux qui sont coincés avec la version <4.2 de Bash et qui ne sont pas à l'aise avec les solutions de contournement proposées, je partage mon implémentation personnalisée de tableaux associatifs globaux. Il n’a pas toute la puissance des tableaux associatifs bash et vous devez faire attention aux caractères spéciaux dans l’index de tableau, mais le travail doit être fait.

get_array(){
   local arr_name="$1"
   local arr_key="$2"

   arr_namekey_var="ASSOCARRAY__${arr_name}__${arr_key}"
   echo "${!arr_namekey_var:=}"
}

set_array(){
   local arr_name="$1"
   local arr_key="$2"
   local arr_value="$3"

   arr_namekey_var="ASSOCARRAY__${arr_name}__${arr_key}"
   if [[ -z "${arr_value}" ]]; then
      eval ${arr_namekey_var}=
   else
      printf -v "${arr_namekey_var}" "${arr_value}"
   fi
}

Quelques notes:

  • Le nom et la clé du tableau peuvent être combinés en une seule valeur, mais la scission s’avère pratique dans la pratique.
  • __ en tant que séparateur peut être piraté par une utilisation malveillante ou négligente - pour être sûr, n'utilisez que des valeurs de soulignement simple dans le nom et la clé du tableau, en plus des valeurs alphanumériques. Bien entendu, la composition de la variable interne (séparateurs, préfixe, suffixe, etc.) peut être adaptée aux besoins de l'application et du développeur.
  • Le développement de valeur par défaut garantit que la clé de tableau non définie (ainsi que le nom du tableau!) Sera étendue à une chaîne nulle.
  • Une fois que vous passez à la version de bash où vous êtes familiarisé avec les tableaux associatifs intégrés, ces deux procédures peuvent être utilisées comme wrappers pour les tableaux associatifs réels sans avoir à refactoriser la base de code entier.
0
Blaf