まれな配列

まれな配列

Bashのマニュアルページでは、名前付き${!a}変数の内容を返す方法(間接レベル)について説明します。a

これを使って配列のすべての要素を返す方法を知りたいです。

a=(one two three)
echo ${a[*]}

返品

one two three

私が欲しい:

b=a
echo ${!b[*]}

同じものを返します。残念ながらそうではなく、代わりに返されます0

修正する

答えを聞いてみると、私の例は次のように単純すぎるということに気づきました。

b=("${a[@]}")

私が必要だと言うすべてを達成します。

だからこれは私の状況です。努力するすること:

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST=LIST_$whichone
LIST=${!_LIST[*]}

もちろん、Bashのマニュアルページを詳しく見てみると、最後の行は単に「配列」のインデックス$_LIST(まったく配列ではない)を返すので、これは期待どおりに機能しないことがわかります。

とにかく、以下は(指示どおり)操作を実行する必要があります。

LIST=($(eval echo \${$_LIST[*]}))

または...(私が選択したパス):

LIST_lys="lys1 lys2"
...
LIST=(${!_LIST})

もちろん、これは要素にスペースが含まれていないと仮定します。

答え1

私はbash変数への間接参照の使用を文字通り受け入れるべきだと思います。

例えば。元の例の場合:

a=(one two three)
echo ${a[*]} # one two three
b=a
echo ${!b[*]} # this would not work, because this notation 
              # gives the indices of the variable b which
              # is a string in this case and could be thought
              # as a array that conatins only one element, so
              # we get 0 which means the first element
c='a[*]'
echo ${!c} # this will do exactly what you want in the first
           # place

最後の実際のシナリオでは、以下のコードがこれを行うと信じています。

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST="LIST_$whichone"[*]
LIST=( "${!_LIST}" ) # Of course for indexed array only 
                     # and not a sparse one

"${var[@]}"混乱$IFSや議論の拡張を避ける表記法を使用することをお勧めします。これが最終コードです。

LIST_lys=(lys1 lys2)
LIST_diaspar=(diaspar1 diaspar2)

whichone=$1   # 'lys' or 'diaspar'

_LIST="LIST_$whichone"[@]
LIST=( "${!_LIST}" ) # Of course for indexed array only 
                     # and not a sparse one
                     # It is essential to have ${!_LIST} quoted

答え2

要素を明示的にコピーする必要があります。インデックス配列の場合:

b=("${a[@]}")

連想配列の場合(a値が配列変数の名前である変数ではなく、配列変数の名前に注意してください):

typeset -A b
for k in "${!a[@]}"; do b[$k]=${a[$k]}; done

配列に変数名がある場合は、追加の手順で要素固有の方法を使用してキーを取得できます。

eval "keys=(\"\${!$name[@]}\")"
for k in "${keys[@]}"; do eval "b[\$k]=\${$name[\$k]}"; done

(警告:この記事のコードはブラウザに直接入力され、テストされていません。)

答え3

${!b[*]}arrayで使用されているインデックスに展開されますb

必要な作業は2段階で行う必要があるため、次のことがeval役に立ちますeval echo \${$b[*]}。 (\最初の$ステップである変数拡張を通過し、2番目のステップでのみ拡張を通過することを保証しますeval。)

パラメータ拡張に応じて、どちらも間接拡張()、接頭辞付きの名前()、および配列キーのリスト()と一致するために!使用されます。配列キーのリストは、予想される間接拡張+配列要素拡張と同じ構文を持ち、後者はサポートされません。{!a}${!a*}${!a[*]}

答え4

配列に間接的にアクセスするには、[@]間接変数に追加するだけですb=a[@]

この変数が設定されている場合:

a=(one two three)
printf '<%s> ' "${a[@]}"; echo

その後、次のように動作します。

b="a[@]"
printf '<%s> ' "${!b}"

または簡単に:

echo "${!b}"

これらの配列は次のようにコピーできます。

newArr=( "${!b}" )

その後、印刷します。

declare -p newArr

スクリプトから:

#!/bin/bash
a=(one two three)
echo "original array"
printf '<%s> ' "${a[@]}"; echo

echo "Indirect array with variable b=a[@]"
b="a[@]"
printf '<%s> ' "${!b}"; echo

echo "New array copied in newArr, printed with declare"
newArr=( "${!b}" )
declare -p newArr

もちろん、上記のすべての操作は非疎配列をコピーします。すべてのインデックスに値があります。

まれな配列

スパース配列は、未定義の要素を含めることができる配列です。
たとえば、a[8]=1234要素を定義しましたが、bashには0〜7はありません。

これらのスパース配列をコピーするには、この方法を使用します。

  1. 前の配列を印刷します。

    $ oldarr[8]=1234
    $ declare -p oldarr
    declare -a oldarr=([8]="1234")
    
  2. 配列の名前を変更して文字列をキャプチャします。

    $ str=$(declare -p oldarr | sed 's/oldarr=/newarr=/')
    
  3. このように生成された文字列を評価して新しい配列を定義しました。

    $ eval "$str"
    $ declare -p newarr
    declare -a newarr=([8]="1234")
    

関連情報