Hacer referencia a variables de matriz bash de otra matriz

8

Quiero escribir un script para hacer referencia a múltiples matrices de otra matriz que contiene los nombres de las variables de estas.

Aquí está mi código hasta ahora:

#!/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

Me gustaría que la salida escanee a través de ambas matrices (desde el bucle externo) e imprima las cadenas respectivas en el bucle interno que llama echo. Mi salida actual solo me muestra:

array1
array2

Le agradecería cualquier sugerencia con respecto a esto. ¡Gracias!

chnppp
fuente
¿Hay alguna razón por la que no puedes simplemente hacer for b in "${array1[@]}" "${array2[@]}"; do ...; done?
Kusalananda
Me gustaría que el número de matrices sea flexible. Por lo tanto, si agrego una matriz más tarde, simplemente la agregaría a array_names y dejaría que el bucle se encargue de ello.
chnppp
Creo que este es un caso de expansión indirecta. Vea stackoverflow.com/questions/8515411/… , pero, básicamente, cambiar ${a[@]}a ${!a}hacer lo que quiere (creo).
parkamark
1
@parkamark No, eso solo le da el primer elemento de cada matriz. Y ${!a[@]}da una longitud de la matriz a.
Kusalananda
Sí, cambiar a ${!a}es solo darme los primeros elementos.
chnppp

Respuestas:

7

Bash 4.3 y posterior admite "referencias de nombre" o namerefs (existe un concepto similar ksh93, pero el alcance es muy diferente ):

#!/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 arres un nameref que actúa como un alias para la variable nombrada (la variable con nombre $aen este ejemplo).

Sin namerefs, en versiones anteriores de Bash, una solución sería crear una nueva matriz que contenga todos los elementos de las otras matrices:

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

... un poco como la array_namesmatriz en la pregunta pero con el contenido de todas las matrices, y luego repetir "${all[@]}".

También es posible usarlo eval, pero el código resultante se ve increíblemente horrible.

Vea la respuesta de Glenn Jackman para una variación con indirección variable (introducida en su forma actual con Bash versión 2).

Kusalananda
fuente
0

Como una variación de lo que se ha dicho:

#!/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

Accediendo a los elementos por índice

Chris
fuente