%20%E3%81%A8%20array%3D(%20%24(%20command%20)%20)%20%E4%BD%BF%E7%94%A8%E3%81%AE%E9%85%8D%E5%88%97%E5%8B%95%E4%BD%9C%E3%81%AE%E9%81%95%E3%81%84%E3%81%AF%E4%BD%95%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F.png)
私はコマンドの置き換えを理解しています。私はサブシェルを理解しています。サブシェルを使用すると、配列の構造が変わる理由を理解できません。
次のコマンド出力を提供します。 (openstackコマンドの使用は関係ありません)
bash$ floating ip list -c 'Floating IP Address' -f value
172.25.250.106
172.25.250.107
172.25.250.101
配列からキャプチャしようとしましたが、すべてのアドレスは要素0で終わります。
bash$ float=$( openstack floating ip list -c 'Floating IP Address' -f value )
bash$ echo ${float[@]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[@]}
1
bash$ echo ${float[0]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[0]}
44
完全な出力は文字列としてキャプチャされ、要素として解析されません。私はすべての単語が一つの要素になることを期待しています。各IPアドレスが参照されていることを確認するためにこの操作を繰り返す(-f値の代わりに-f csvを使用)、結果は同じです。
次に、コマンド置換をサブシェルに入れます。
bash$ unset float
bash$ float=( $( openstack floating ip list -c 'Floating IP Address' -f value ) )
bash$ echo ${float[@]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[@]}
3
echo ${float[0]}
172.25.250.106
echo ${#float[0]}
14
これが私がもともと期待していた動作です。また、配列を構築するためにread文を使用することが期待どおりに機能することを確認しました。
bash$ unset float
bash$ read -a float <<< $( openstack floating ip list -c 'Floating IP Address' -f value )
bash$ echo ${float[@]}
172.25.250.106 172.25.250.107 172.25.250.101
bash$ echo ${#float[@]}
3
echo ${float[0]}
172.25.250.106
echo ${#float[0]}
14
元のコマンド置換操作を見たいです。フィールド区切り文字を最初に設定する必要があるのか、それとも何かが欠けているのだろうか。私は行動の違いを引き起こす原因を理解しようとしています。
答え1
float=$( openstack floating ip list -c 'Floating IP Address' -f value )
これはひも配列変数ではなく変数です。文字列は、末尾の改行を引いたコマンドの出力です。
文字列変数を配列として使用しようとすると、位置0に文字列値を持つ単一要素配列として扱われます。
float=( $( openstack floating ip list -c 'Floating IP Address' -f value ) )
これは、「コマンド置換をサブシェルに入れる」ことではありません。コマンド置換自体が$(…)
サブシェルを生成します。周囲の括弧は、他のサブシェルを生成せずに配列を生成します。配列の内容はコマンドの出力を取り、末尾の改行を削除し、スペースで区切られた単語のリストに分割し、1つ以上のファイルに一致するワイルドカードを含むこのリストのすべての要素に一致するファイル名のリストで置き換えて得ます。
コマンドが予想される場所に角かっこを配置すると、サブシェルが生成されます。でvar=(…)
等号の後に続くのは、コマンドではなく割り当てられた値です。この場合、角括弧は値が配列であることを示します。
答え2
float=$( openstack floating ip list -c 'Floating IP Address' -f value )
これはコマンドの置き換え内部に一つ一般変数の割り当て、配列の割り当てではありません。すべての複合配列割り当てには次の形式があります。x=( ... )
、以下で使用するように。これにはサブシェルはありません(単に代替コマンドの実行コンテキストとして機能することを除く)。
コマンド置換を使用すると、その内容を含む変数がその場所で動作するのと同じ方法で動作するため、ここでは同様ですが、float=$x
またはls $x
同様ですfoo=($x)
。噴射拡張結果に対して実行され、変数のすべての文字から値を別々の引数に分割しますIFS
。
引用符の拡張により、単語の分離を抑制できます"$(...)"
。
分割された単語の配列を作成するには、次のものが必要です。両方配列を作成し、分割という単語を取得します。これは、2番目の場合のように、foo=(...)
パラメータまたはコマンド置換と$...
組み合わせた配列割り当てを意味します。
float=( $( openstack floating ip list -c 'Floating IP Address' -f value ) )
float=(...)
コマンドの置換中に実行されたトークン化から要素を取得した配列を作成します$(...)
。
混乱する可能性があるのは、配列以外の項目を配列として使用すると、Bashが自動的にそれをシングルトン配列に変換するため、配列を取得するように見えますが、項目は1つです。
echo ${float[0]}
echo ${#float[@]}
これはとてもスマートに録音した:
有効な添え字を使用した変数への参照はすべて有効で、必要に応じてbashは配列を生成します。
異なるインデックスを使用すると、これをより明確に表示できます。
float[1]=abc
echo ${#float[@]} # => 2
変換プロセスでは、変数の既存の値(存在する場合)のみが配列のインデックス0の項目として使用されます。
答え3
括弧はvar=( some things )
サブシェルを表示しません。配列割り当て構文。したがって、それらがない場合は、一般(スカラー)変数に割り当てられます。一般割り当ての右側はトークン化されていないため、文字列がvar=$(echo foo bar)
入り、スペースが追加されます。一方、配列の割り当てには複数の単語が必要なため、両方の単語は2要素の配列を提供します。foo bar
var
arr=(foo bar)
arr=( $(echo foo bar) )