Como adicionar valores a uma matriz que contém uma variável no nome da matriz no bash?

1

Eu tenho um array no meu script que leva uma lista de nomes de grupos. Esta lista não possui um número fixo de elementos.

GROUPS=(group1 group2 group3)

Cada elemento neste conjunto de GRUPOS pode ter um número desconhecido de valores. Eu dinamicamente criar um conjunto de matrizes com uma variável no nome onde VARIABLE é o nome do grupo:

for VARIABLE in "${GROUPS[@]}"
do
  declare -a ARRAY_${VARIABLE}
done

Eu quero fazer uma iteração por meio de um conjunto de valores e, se uma condição for atendida, inclua-os na matriz à qual eles pertencem como novos elementos.

for (( VALUES=1; VALUES<=10; VALUES++ ));
do 
  if the VALUE belongs to GROUPx assign it to the array for GROUPx 
    ARRAY_$VARIABLE+=("$VALUES")
  fi
done

Isso deve acabar com um conjunto de matrizes que contêm valores que pertencem aos grupos, ou seja:

ARRAY_group1= 1 2 5 9 10
ARRAY_group2= 3 7 
ARRAY_group3= 4 6 8

Mas eu sempre recebo o erro bash: syntax error near unexpected token '"$ VALUES"'. Se eu estou apenas atribuindo-o a uma matriz chamada ARRAY, ele funciona perfeitamente, mas eu tenho que atribuir valores no meu script para um número desconhecido de matrizes que precisam ser criados dinamicamente.

Eu poderia adicionar os valores a uma string cujo nome contém uma variável com concatenação e depois usar sed para selecionar valores individuais, mas também não consigo encontrar a sintaxe correta para essa expressão.

let TEST_$VARIABLE="$TEST_$VARIABLE:$VALUES"
let TEST_$VARIABLE="${TEST_$VARIABLE}:$VALUES"
let TEST_$VARIABLE="$((TEST_$VARIABLE)):$VALUES"
let TEST_$VARIABLE="$((TEST_$VARIABLE))" ":$VALUES"

Eu tentei algumas outras coisas, mas todas elas se depararam com o mesmo problema, bash realmente não gosta de variáveis sendo usadas no nome da variável, mas devo criá-las dinamicamente, o que significa que eu tenho que ter uma variável no nome.

Eu tentei algumas outras coisas, mas se você sabe como se referir a uma variável que contém uma variável em seu nome confiável no bash para que eu possa evitar todos os erros de sintaxe e erros de substituição ruins eu agradeceria muito.

Tldr: Existe alguma sintaxe que eu possa usar para obter o bash para tratar ARRAY_ $ VARIABLE [@] da mesma maneira que o bash trata ARRAY [@]

    
por Michael Lafleur 14.02.2018 / 22:52

1 resposta

0

namerefs

Eu acho que um nameref seria o que você quer:

name=foo
declare -a array_$name
declare -n target=array_$name
for x in asdf 'white space' ; do target+=("$x"); done 
declare -p array_$name

saídas:

declare -a array_foo=([0]="asdf" [1]="white space")

eval, declare, deixe

O outro, pior, seria usar eval ou declare para definir os valores.

eval fica complicado com as citações, você não deseja expandir acidentalmente $ s dentro de seus valores.

eval "array_$name+=(\"\$x\")"

declare torna um pouco duvidoso implementar o acréscimo ao array. No entanto, é bastante simples se você conhece o índice para atribuir a:

declare "array_$name[$i]=$x"

(Obtendo o número de elementos em array_$name parece exigir nameref ou eval novamente.)

Você mencionou let ; é um pouco como declare aqui, mas funciona com expressões aritméticas, então não é um bom ajuste para o caso geral.

name=a; 
let "test_$name=12+34"        # sets test_a to 46
let "test_$name=foo"          # reads the _value_ of variable foo!
let "test_$name=foo bar"      # this is an error.

estruturas de dados alternativas

Como alternativa, se houver apenas um de cada valor, inverta a estrutura de dados e armazene o ID do grupo de cada valor em uma única matriz:

for (( val=1; val <= 10; val++ )); do
     groupid=$(find_groupid "$val")
     variables[$val]=$groupid
done

Em seguida, percorra toda a matriz e ignore os grupos nos quais você não está interessado.

Ou, se seus valores não contiverem espaços em branco, apenas use strings para os arrays internos. Para fazer um loop sobre eles, faça algo como

for group in "${groups[@]}"; do 
    for item in $group; do       # no quotes here, we want wordsplitting
        ...

(ou use um array associativo lá para armazenar os nomes dos grupos também).

    
por 14.02.2018 / 23:13