按子字符串循环关联数组

按子字符串循环关联数组

在下面的代码中,我在循环中创建一些关联数组。它由两个字符串组成,一个字符串标识符和一个年份。创建后,我想仅根据标识符在循环中访问数组。

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

A_1999在这里,我很容易得到一堆例如扩展为JF-1999 JFE-1999 RFS-1999等形式的数组。

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

我预计

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

bad substitution error一直都得到一个,并且尝试了很多组合。怎么了?

答案1

欢迎来到eval 地狱!一旦你开始使用它,你就永远不会摆脱它。

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

可能有更好的方法来做到这一点,但我从不费心在 shell 脚本中使用关联数组或其他嵌套数组。如果您需要此类数据结构,那么使用本身支持它们的脚本语言可能会更好。

实际上,bash 在某种程度上支持关联数组。它们是否对您有用是另一个问题,无论如何它都不能移植到其他 shell。

答案2

变量间接在这里会有帮助:

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

输出

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

无需评估的重写。数组的数组不是 bash 本身适合的东西,所以我必须使用空格分隔的字符串和临时存储

# 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

答案3

我认为 bash 的数组存在一些误解:

数组

   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.

相关内容