Référencement des variables de tableau bash à partir d'un autre tableau

8

Je veux écrire un script pour référencer plusieurs tableaux d'un autre tableau qui contient les noms de variables de ces tableaux.

Voici mon code jusqu'à présent:

#!/bin/bash
array1=('array1string1' 'array1string2')
array2=('array2string1' 'array2string2')

array_names=('array1' 'array2')

for a in ${array_names[@]}
do
        for b in ${a[@]}
        do
                echo $b
        done
done

J'aimerais que la sortie balaye les deux tableaux (depuis la boucle for externe) et imprime les chaînes respectives dans la boucle for interne qui appelle l'écho. Ma sortie actuelle me montre juste:

array1
array2

Je serais reconnaissant à tout pointeur à ce sujet. Je vous remercie!

chnppp
la source
Y a-t-il une raison pour laquelle vous ne pouvez pas simplement faire for b in "${array1[@]}" "${array2[@]}"; do ...; done?
Kusalananda
J'aimerais que le nombre de tableaux soit flexible. Par conséquent, si j'ajoute un tableau plus tard, je l'ajouterais simplement à array_names et laisserais la boucle s'en occuper.
chnppp
Je pense que c'est un cas d'expansion indirecte. Voir stackoverflow.com/questions/8515411/… - mais, en gros, changer ${a[@]}pour ${!a}fait ce que vous voulez (je pense).
parkamark
1
@parkamark Non, cela lui donne juste le premier élément de chaque tableau. Et ${!a[@]}donne une longueur du tableau a.
Kusalananda
Oui, passer à ${!a}me donne juste les premiers éléments.
chnppp

Réponses:

7

Bash 4.3 et versions ultérieures prennent en charge les «références de nom», ou namerefs (un concept similaire existe ksh93, mais la portée est énormément différente ):

#!/bin/bash

array1=('array1string1' 'array1string2')
array2=('array2string1' 'array2string2')

array_names=('array1' 'array2')

for a in "${array_names[@]}"; do
    declare -n arr="$a"

    for b in "${arr[@]}"; do
        echo "$b"
    done
done

La variable arrest un nom qui agit comme un alias pour la variable nommée (la variable avec nom $adans cet exemple).

Sans namerefs, dans les versions précédentes de Bash, une solution serait de créer un nouveau tableau contenant tous les éléments des autres tableaux:

all=( "${array1[@]}" "${array2[@]}" )

... un peu comme le array_namestableau dans la question mais avec le contenu de tous les tableaux, puis répétez "${all[@]}".

Il est également possible de l'utiliser eval, mais le code résultant est incroyablement horrible.

Voir la réponse de glenn jackman pour une variation avec indirection variable (introduite dans sa forme actuelle avec Bash version 2).

Kusalananda
la source
3

@Kusalananda a la meilleure réponse pour les versions récentes de bash. Pour les versions antérieures, vous pouvez utiliser une variable indirecte:

for a in ${array_names[@]}; do 
    tmp="${a}[@]"
    for b in "${!tmp}"; do echo "$b"; done     # or: printf "%s\n" "${!tmp}"
done

Voir le 4ème paragraphe de https://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion

glenn jackman
la source
0

En variante de ce qui a été dit:

#!/bin/bash

array1=('array1 string1' 'array1 string2')
array2=('array2 string1' 'array2 string2')
array_names=('array1' 'array2')

for (( i=0; i<${#array_names[@]}; i++ )); do

    declare -n arr="${array_names[i]}"

    for (( j=0; j<${#arr[@]}; j++ )); do
        echo "${arr[j]}"
    done

done

Accéder aux éléments par index à la place

chris
la source