Referenciando variáveis de matriz bash de outra matriz

6

Eu quero escrever um script para fazer referência a vários arrays de outro array que contém os nomes das variáveis desses arrays.

Aqui está meu código até agora:

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

Eu gostaria que a saída varresse pelas duas matrizes (do loop for externo) e imprimisse as respectivas cadeias no loop for interno que chama echo. Minha saída atual está apenas me mostrando:

array1
array2

Eu ficaria grato por qualquer indicação sobre isso. Obrigada!

    
por chnppp 06.09.2017 / 19:12

3 respostas

4

Bash 4.3 e posterior suporta "referências de nomes", ou namerefs (existe um conceito semelhante em ksh93 , mas o escopo é irritantemente 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

A variável arr é um nameref que age como um alias para a variável nomeada (a variável com o nome $a neste exemplo).

Sem namerefs, nas versões anteriores do Bash, uma solução seria criar um novo array que contenha todos os elementos dos outros arrays:

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

... um pouco como a matriz array_names na pergunta, mas com o conteúdo de todas as matrizes, e depois iterar sobre "${all[@]}" .

Também é possível usar eval , mas o código resultante parece incrivelmente terrível.

Veja a resposta de glenn jackman para uma variação com a indirecção variável (introduzida na sua forma atual com Bash versão 2) .

    
por 06.09.2017 / 19:38
2

@ Kusalananda tem a melhor resposta para versões recentes do bash. Para versões anteriores, você pode usar uma variável indireta:

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

Veja o quarto parágrafo do link

    
por 06.09.2017 / 19:56
0

Como uma variação do que foi dito:

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

Acessando os elementos por índice, em vez

    
por 09.09.2017 / 07:45