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

Но это что уродливые заявление случай в середине и не столь гибки, как это могло быть. Я хотел бы иметь возможность расширять его без необходимости расширять деловую форму.

Я попытался это:

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 

Есть ли какая-синтаксический магия, которая позволила бы мне динамически определять и имена массивов доступа? Любая помощь приветствуется.

Я попытался "Михась" решение, как показано здесь:

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

ОК, решить мой проблема. Этот цикл работает как первый (все еще ограниченный, но теперь ограничен строками без «+»), но я могу любить с этим.

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

Приведет страницу человека Баша:

${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

Смежные вопросы