2013-10-27 70 views
2

有没有一种方法来动态访问数组名称?Bash数组名称选择

下面的循环工作原理:

#!/bin/bash 

for i in 1 2 3 4 5; do 
    for j in 1 2 3 4 5; do 
     state="i=$i, j=$j" 
     case "$i" in 
      1) p_1+=("$state");; 
      2) p_2+=("$state");; 
      3) p_3+=("$state");; 
      4) p_4+=("$state");; 
      5) p_5+=("$state");; 
      *) break;; 
     esac 
    done 
done 
for i in {0..5}; do echo "${p_1[$i]}"; done 
for i in {0..5}; do echo "${p_2[$i]}"; done 
for i in {0..5}; do echo "${p_3[$i]}"; done 
for i in {0..5}; do echo "${p_4[$i]}"; done 
for i in {0..5}; do echo "${p_5[$i]}"; done 

输出看起来像:

i=1, j=1 
i=1, j=2 
i=1, j=3 
i=1, j=4 
i=1, j=5 

i=2, j=1 
i=2, j=2 
i=2, j=3 
i=2, j=4 
i=2, j=5 

i=3, j=1 
i=3, j=2 
i=3, j=3 
i=3, j=4 
i=3, j=5 

i=4, j=1 
i=4, j=2 
i=4, j=3 
i=4, j=4 
i=4, j=5 

i=5, j=1 
i=5, j=2 
i=5, j=3 
i=5, j=4 
i=5, j=5 

但是它有一个丑陋的case语句在中间,不灵活,因为它可以。我希望能够扩大它,而不必扩大案件陈述。

我尝试这样做:

for i in 1 2 3 4 5; do 
    for j in 1 2 3 4 5; do 
     $(p_${i})+=("$i, j=$j") # Does not work 
     ${p_$i}+=("$i, j=$j") # neither does this 
    done 
done 

有一些语法魔力,让我来动态定义和访问数组的名字呢?任何帮助是极大的赞赏。

我试过 “michas” 的解决方案,如下所示:

#!/bin/bash 
for i in 1 2 3 4 5; do 
    for j in 1 2 3 4 5; do 
     state=("i=$i, j=$j") 
     eval "p_$i+=($state)" 
     #also tried 
     # IFS="_" state=("i=$i,j=$j") #failed to show j= 
     # IFS="_" eval "p_$i=($state)" # failed to show j= 
    done 
done 
for i in {0..5}; do 
    for j in {0..5}; do 
     res=p_$i 
     eval "echo \$p_$i cooked: ${!res}" 
     #IFS="_" eval "echo \$p_$i cooked: ${!res}" #failed to show j= 
    done 
done 

但即使注释掉地区,所有返回以下(有删节)输出:

i=1, cooked: i=1, 
: 
i=1, cooked: i=1, 
i=1, cooked: i=1, 
: 
i=3, cooked: i=3, 
i=3, cooked: i=3, 
    : 
i=4, cooked: i=4, 
i=4, cooked: i=4, 
    : 
i=5, cooked: i=5, 
i=5, cooked: i=5, 

OK,解决了我问题。这个循环作为第一个(仍然有限,但现在仅限于没有“+”的字符串),但我可以喜欢这个。

#!/bin/bash 
for i in 1 2 3 4 5; do 
    for j in 1 2 3 4 5; do 
     state=$(echo "i=$i, j=$j" | tr " " "+") 
     eval "p_$i+=($state)" 
    done 
done 


for i in {0..5}; do 
    for j in {0..5}; do 
     res=p_$i[$j] 
     eval "echo ${!res}"| tr '+' ' ' 
    done 
done 

谢谢!

回答

2
p_5=foo 
i=5 
v=p_$i 
echo ${!v} 
# => foo 

让我们举bash手册页:

${parameter} 
      The value of parameter is substituted. The braces are required 
      when parameter is a positional parameter with more than one 
      digit, or when parameter is followed by a character which is not 
      to be interpreted as part of its name. 

    If the first character of parameter is an exclamation point (!), a 
    level of variable indirection is introduced. Bash uses the value of 
    the variable formed from the rest of parameter as the name of the vari‐ 
    able; this variable is then expanded and that value is used in the rest 
    of the substitution, rather than the value of parameter itself. This 
    is known as indirect expansion. The exceptions to this are the expan‐ 
    sions of ${!prefix*} and ${!name[@]} described below. The exclamation 
    point must immediately follow the left brace in order to introduce 
    indirection. 

但这只能用于访问的价值和不可移植的其他炮弹。

作为替代方案,你可以随时使用eval

p_5=foo 
i=5 
eval "echo \$p_$i" # => foo 
eval "p_$i=bar" 
echo $p_5 # => bar 

手册页说:

eval [arg ...] 
      The args are read and concatenated together into a single com‐ 
      mand. This command is then read and executed by the shell, and 
      its exit status is returned as the value of eval. If there are 
      no args, or only null arguments, eval returns 0. 
+0

你是正确的,我应该有RTFM,但该解决方案没有奏效。数组间分隔符的IFS设置似乎有问题。我还尝试添加更改赋值为:“IFS =”_“state =(”i = $ i,j = $ j“),并且也在eval命令中:例如IFS =”_“eval”p_ $ i =( $ state)“,无论我尝试什么,我都无法让它显示”j“设置。使用你的方法,似乎将数组元素分割在”“边界上,谢谢。 – lcollado