在下面的代码中,我在循环中创建一些关联数组。它由两个字符串组成,一个字符串标识符和一个年份。创建后,我想仅根据标识符在循环中访问数组。
#!/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.