web-dev-qa-db-ja.com

bash変数の間接参照を使用するときに、配列のその他のメンバーにアクセスするにはどうすればよいですか?

次の例を考えてみましょう。インデックス0で正常に機能しているようです。

$ a1=(1 2 3)
$ a2=(a b c)
$ for x in a1 a2; do echo "${!x}"; done
1
a
$ for x in a1 a2; do echo "${!x[0]}"; done
1
a

ただし、インデックス1を使用すると、何も出力されません。

$ for x in a1 a2; do echo "${!x[1]}"; done    

配列だけでも問題ありません。

$ echo "${a1[1]} ${a2[1]}"
2 b

編集ilkkach回答に基づく実際のユースケース

SHIBB=(https://shibboleth.net/downloads/service-provider/3.0.2/ shibboleth-sp-3.0.2 .tar.gz)
XERCES=(http://Apache.mirrors.nublue.co.uk//xerces/c/3/sources/ xerces-c-3.2.1 .tar.gz)
XMLSEC=(http://Apache.mirror.anlx.net/santuario/c-library/ xml-security-c-2.0.1 .tar.gz)
XMLTOOL=(http://shibboleth.net/downloads/c++-opensaml/latest/ xmltooling-3.0.2 .tar.gz)
OPENSAML=(http://shibboleth.net/downloads/c++-opensaml/latest/ opensaml-3.0.0 .tar.gz)

typeset -n x
for x in XERCES XMLSEC XMLTOOL OPENSAML SHIBB; do
  url="${x[0]}" app="${x[1]}" ext="${x[2]}"
  [ -f "./${app}${ext}" ] || wget "${url}${app}${ext}"
  tar -xf "./${app}${ext}"
  cd "./${app}" && ./configure && make -j2 && make install && ldconfig
  cd ..
done
2
NarūnasK

"${!x[1]}"は、配列xのインデックス1にある要素を使用した間接参照です。

$ foo=123; bar=456; x=(foo bar); echo "${!x[1]}"
456

Bashの現在のバージョン(4.3以降)では、namerefsを使用して必要なものを取得できます。

$ a=(00 11 22 33 44)
$ typeset -n y=a
$ echo "${y[3]}"
33

つまり、namerefが設定されている場合、"${y[3]}"は、yという名前の配列内の要素3への参照です。


質問のように配列をループするには、xをnamerefにするだけです。

a1=(1 2 3); a2=(a b c)
typeset -n x;
for x in a1 a2; do
    echo "${x[1]}"
done

forループによって行われる割り当ては、x自体の値を変更します(参照が指すものを変更します)。通常の割り当て(x=123、またはx[1]=123)は、現在xによって参照されている変数を変更します。したがって、これによりa1[1]a2[1]の両方がfooに変更されます。

typeset -n x;
for x in a1 a2; do
    x[1]=foo
done

"${!x[0]}"が機能しているように見える理由は、xx[0]が同等であるためです。ループ内にecho "${x[0]}"がある場合(強打なし)、a1と同じように、a2echo "$x"を取得します。

6
ilkkachu

間接参照は、one値を展開し、展開の結果を変数のnew名前として使用することで機能します。

$ a=abc; x=a; echo "${!x}"
abc

$ a=(one two three four); x=a[0]; y=a[1]; z=a[3]; echo "${!x}   ${!y}   ${!z}"
one   two   four

だから、あなたの例のために:

$ a1=(1 2 3);   a2=(a b c)
$ for x in a1[0] a2[0] a1[1] a1[2]; do echo "${!x}"; done
1
a
2
b

「実際のユースケース」では、次のことができます。

SHIBB=(https://shibboleth.net/downloads/service-provider/3.0.2/ shibboleth-sp-3.0.2 .tar.gz)
XERCES=(http://Apache.mirrors.nublue.co.uk//xerces/c/3/sources/ xerces-c-3.2.1 .tar.gz)
XMLSEC=(http://Apache.mirror.anlx.net/santuario/c-library/ xml-security-c-2.0.1 .tar.gz)
XMLTOOL=(http://shibboleth.net/downloads/c++-opensaml/latest/ xmltooling-3.0.2 .tar.gz)
OPENSAML=(http://shibboleth.net/downloads/c++-opensaml/latest/ opensaml-3.0.0 .tar.gz)

for s in XERCES XMLSEC XMLTOOL OPENSAML SHIBB; do
    x=${s}[0] y=${s}[1] z=${s}[2]
    url="${!x}" app="${!y}" ext="${!z}"
    [ -f "./${app}${ext}" ] || wget "${url}${app}${ext}"
    tar -xf "./${app}${ext}"
    cd "./${app}" && ./configure && make -j2 && make install && ldconfig
    cd ..
done
0
Isaac