Cria arrays com expansão de chave em loop

4

Eu gostaria de gerar um número de matrizes que diferem apenas por ano. No loop, crio os arrays com expansão de chave e uma variável.

Eu tentei o seguinte código sem sucesso:

LIST={JF,JFE,RFS,JBF,JFI,JMCB}
for year in {1998..2000} {2009..2011}
do
  declare -a 'y$year=('"$LIST"'-$year)'
  echo "${y$year[@]}"
done

O resultado deve ser a lista das seguintes entradas:

y1998: JF-1998 JFE-1998 RFS-1998 JBF-1998 JFI-1998 JMCB-1998
y1999: JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999
...
y2011: JF-2011 JFE-2011 RFS-2011 JBF-2011 JFI-2011 JMCB-2011

Eu não preciso imprimi-los, basta usá-los em um loop, bem como passá-los como argumentos. Por causa do segundo, eval no loop não é suficiente.

    
por MERose 29.12.2014 / 01:35

3 respostas

6

Adiar a expansão de chaves é realmente um caso para eval , particularmente Se você quiser restringir as coisas - expansão de parâmetro comum não faz a coisa certa no momento certo.

Isso deve fazer o que parece que você queria:

LIST={JF,JFE,RFS,JBF,JFI,JMCB}
for year in {1998..2000} {2009..2011}
do
  eval "y$year=($LIST-$year)"
  tmp="y$year[@]"
  echo "${!tmp}"
done

Você não pode indiretamente em uma matriz, portanto, é necessário que a matriz seja restrita dentro de eval também se você quiser imprimi-la. Se não, você pode retirar tudo depois do ; . tmp é usado para expansão indireta : com tmp definido como "y$year[@]" , onde $year é substituído por seu valor, a expansão ${!tmp} fornece o conteúdo da matriz desta iteração (o que ${y1998[@]} , etc, teria se expandido para).

O texto acima será exibido:

JF-1998 JFE-1998 RFS-1998 JBF-1998 JFI-1998 JMCB-1998
JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999
JF-2000 JFE-2000 RFS-2000 JBF-2000 JFI-2000 JMCB-2000
JF-2009 JFE-2009 RFS-2009 JBF-2009 JFI-2009 JMCB-2009
JF-2010 JFE-2010 RFS-2010 JBF-2010 JFI-2010 JMCB-2010
JF-2011 JFE-2011 RFS-2011 JBF-2011 JFI-2011 JMCB-2011

e também criar matrizes y1998 ... y2011 . Os declare s não são estritamente necessários, embora eles deixem você pular um eval se você está apontando para isso e não precisa se restringir.

Eu sugiro que isso provavelmente não seja o jeito que você realmente deseja alcançar seu objetivo subjacente, seja lá o que for. Loops aninhados não são malvados, e se algum deles for codificado, você pode abstrair isso.

    
por 29.12.2014 / 02:10
4

Aqui está uma maneira (com expansão de chaves) :

unset y _y
for y in {JF,JFE,RFS,JBF,JFI,JMCB,}-{{1998..2000},{2009..2011}}
do  case "${_y=y${y#*-}[@]}"               in 
    (y${y#-}*) echo "${!_y}"               ;; 
    (*)        declare -a "${_y%???}+=($y)";; 
esac; unset y _y; done

Isso expandirá seu conjunto de parâmetros para o loop for para todos os valores desejados mais um último conjunto extra que consistirá apenas nos anos. Para cada um que não começa com um dígito declare adiciona um membro da matriz a qualquer que seja o y${y##*[!0-9]} , e para cada que faz , echo imprime.

Portanto, nas primeiras 36 iterações, ele cria cada array e, nos últimos 6, ele imprime cada uma. A saída é:

JF-1998 JFE-1998 RFS-1998 JBF-1998 JFI-1998 JMCB-1998
JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999
JF-2000 JFE-2000 RFS-2000 JBF-2000 JFI-2000 JMCB-2000
JF-2009 JFE-2009 RFS-2009 JBF-2009 JFI-2009 JMCB-2009
JF-2010 JFE-2010 RFS-2010 JBF-2010 JFI-2010 JMCB-2010
JF-2011 JFE-2011 RFS-2011 JBF-2011 JFI-2011 JMCB-2011

Aqui está uma alternativa, talvez ...

for year in 1998 1999 2000 2009 2010 2011
do  printf "%s-$year " JF JFE RFS JBF JFI JMCB
echo; done

Isso daria pelo menos a mesma saída ... Para também armazenar isso em uma matriz, provavelmente você poderia ...

for year in 1998 1999 2000 2009 2010 2011
do  declare -a "y$year=($(printf "%s-$year " JF JFE RFS JBF JFI JMCB |
               tee /dev/fd/2 ))"
    year=y$year[@]; year=(${!year})
    echo "${#year[@]}"
done 2>&1; unset year

Esta é a saída do segundo comando, mas a primeira imprime a mesma sem o 6 - que apenas indica a contagem de membros da matriz.

JF-1998 JFE-1998 RFS-1998 JBF-1998 JFI-1998 JMCB-1998 6
JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999 6
JF-2000 JFE-2000 RFS-2000 JBF-2000 JFI-2000 JMCB-2000 6
JF-2009 JFE-2009 RFS-2009 JBF-2009 JFI-2009 JMCB-2009 6
JF-2010 JFE-2010 RFS-2010 JBF-2010 JFI-2010 JMCB-2010 6
JF-2011 JFE-2011 RFS-2011 JBF-2011 JFI-2011 JMCB-2011 6

Lembre-se que declare é um comando e o argumento var$expand=(something $expand) é apenas isso - um argumento. Os argumentos de declare são expandidos da mesma maneira que qualquer outro - o que não é verdade para uma instrução var$expand=$expand . Então você pode indiretamente declare da mesma forma que você pode indiretamente export ou o que for - as palavras difíceis que você usa não são necessárias, eu acho.

    
por 29.12.2014 / 02:01
1

Converta a expansão de chave em um array via set -- .

Então você tem um loop bidimensional simples para construir sua saída:

set -- {JF,JFE,RFS,JBF,JFI,JMCB}
for year in {1998..2000} {2009..2011}; do
    printf "y%s: " $year
    for code; do
        printf "%s-%s " $code $year
    done
    echo
done

Rendimentos:

y1998: JF-1998 JFE-1998 RFS-1998 JBF-1998 JFI-1998 JMCB-1998
y1999: JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999
y2000: JF-2000 JFE-2000 RFS-2000 JBF-2000 JFI-2000 JMCB-2000
y2009: JF-2009 JFE-2009 RFS-2009 JBF-2009 JFI-2009 JMCB-2009
y2010: JF-2010 JFE-2010 RFS-2010 JBF-2010 JFI-2010 JMCB-2010
y2011: JF-2011 JFE-2011 RFS-2011 JBF-2011 JFI-2011 JMCB-2011
    
por 21.04.2017 / 15:33