Faz um loop sobre matrizes associativas por substring

2

No código a seguir, eu crio alguns arrays associativos em um loop. A consistir de duas seqüências de caracteres, um identificador de seqüência de caracteres e um ano. Após a criação, desejo acessar as matrizes em um loop com base apenas no identificador.

#!/bin/bash

# Declare associative arrays of journal-year combinations
A_JOURNAL_LIST={JF,JFE,RFS}
B_JOURNAL_LIST={JBF,JFI,JMCB}
ALL_JOURNAL_LIST={JF,JFE,RFS,JBF,JFI,JMCB}
for year in {1998..2000} {2009..2011}
do
  eval "A_$year=($A_JOURNAL_LIST-$year) ;"
  eval "B_$year=($B_JOURNAL_LIST-$year) ;"
  eval "all_$year=($ALL_JOURNAL_LIST-$year) ;"
done  

Aqui eu consigo facilmente um monte de matrizes da forma A_1999 que, por ex. expande para JF-1999 JFE-1999 RFS-1999 e assim por diante.

for journal in A B all
do
  echo "${'$journal'_1999[@]}"
done

Espero que

JF-1999 JFE-1999 RFS-1999
JBF-1999 JFI-1999 JMCB-1999
JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999

Eu ganhei bad substitution error o tempo todo e tentei muitas combinações. O que há de errado?

    
por MERose 29.01.2015 / 15:17

3 respostas

3

indireto de variável será útil aqui:

for journal in A B all
do
    indirect="${journal}_1999[@]"
    echo "$journal: ${!indirect}"
done

saídas

A: JF-1999 JFE-1999 RFS-1999
B: JBF-1999 JFI-1999 JMCB-1999
all: JF-1999 JFE-1999 RFS-1999 JBF-1999 JFI-1999 JMCB-1999

Uma reescrita sem eval. Matrizes de arrays não são algo que o bash é adequado nativamente, então eu tenho que usar strings separadas por espaço e armazenamento temporário

# Declare associative arrays of journal-year combinations
a_journal_list=( {JF,JFE,RFS} )
b_journal_list=( {JBF,JFI,JMCB} )
all_journal_list=( "${a_journal_list[@]}" "${b_journal_list[@]}" )
declare -a a b all

for year in {1998..2000} {2009..2011}
do
    # store year-specific values as space-separated strings
    a[$year]=$( printf "%s-$year " "${a_journal_list[@]}" )
    b[$year]=$( printf "%s-$year " "${b_journal_list[@]}" )
    all[$year]=$( printf "%s-$year " "${all_journal_list[@]}" )
done  

selected_years=( 1998 1999 2000 )
for journal in a b all
do
    # I'll use the positional params for temp storage of the accumulated array
    set --
    for year in "${selected_years[@]}"
    do
        indirect="${journal}[$year]"
        # variable is unquoted to allow word splitting
        set -- "$@" ${!indirect}
    done
    echo $journal
    printf "%s\n" "$@"
done
    
por 29.01.2015 / 15:54
4

Bem-vindo ao eval hell ! Depois de começar a usá-lo, você nunca se livra dele.

for journal in A B all
do
  eval "echo \"\${${journal}_1999[@]}\""
done

Pode haver uma maneira muito melhor de fazer isso, mas nunca me preocupo com matrizes associativas ou aninhadas em scripts de shell. Se você precisar dessas estruturas de dados, talvez seja melhor ter uma linguagem de script que as suporte nativamente.

Na verdade, o bash tem suporte para matrizes associativas depois de uma moda. Se eles podem ser úteis para você é outra questão, não é portável para outros shells em qualquer caso.

    
por 29.01.2015 / 15:31
0

Acho que há alguns arrays de bash mal compreendidos:

Arrays

   Bash provides one-dimensional indexed and associative array variables.  Any variable may be used as  an
   indexed  array; the declare builtin will explicitly declare an array.  There is no maximum limit on the
   size of an array, nor any requirement that members be indexed or assigned contiguously.  Indexed arrays
   are  referenced  using  integers  (including  arithmetic  expressions)  and are zero-based; associative
   arrays are referenced using arbitrary strings.  Unless otherwise noted, indexed array indices  must  be
   non-negative integers.

   An  indexed  array  is  created automatically if any variable is assigned to using the syntax name[sub‐
   script]=value.  The subscript is treated as an arithmetic expression that must evaluate  to  a  number.
   To  explicitly  declare  an  indexed  array,  use  declare  -a name (see SHELL BUILTIN COMMANDS below).
   declare -a name[subscript] is also accepted; the subscript is ignored.

   Associative arrays are created using declare -A name.

   Attributes may be specified for an array variable  using  the  declare  and  readonly  builtins.   Each
   attribute applies to all members of an array.

   Arrays  are  assigned  to  using  compound assignments of the form name=(value1 ... valuen), where each
   value is of the form [subscript]=string.  Indexed array assignments do not require anything but string.
   When  assigning  to  indexed arrays, if the optional brackets and subscript are supplied, that index is
   assigned to; otherwise the index of the element assigned is the last index assigned to by the statement
   plus one.  Indexing starts at zero.

   When assigning to an associative array, the subscript is required.

   This  syntax  is  also  accepted  by the declare builtin.  Individual array elements may be assigned to
   using the name[subscript]=value syntax introduced above.  When assigning to an indexed array,  if  name
   is  subscripted  by  a  negative number, that number is interpreted as relative to one greater than the
   maximum index of name, so negative indices count back from the end of the array, and  an  index  of  -1
   references the last element.
    
por 29.01.2015 / 15:33

Tags