2013-10-27 108 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