2

配列名に動的にアクセスする方法はありますか?

次のループが機能します。

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

ありがとう!。

4

1 に答える 1

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

bash の man ページを引用しましょう。

   ${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.
于 2013-10-27T22:11:22.200 に答える