web-dev-qa-db-ja.com

説明できますか。 array = $(command)とarray =($(command))の使用による配列の動作の違いは?

コマンド置換を理解しています。私はサブシェルを理解しています。サブシェルを使用すると配列の構造が変わる理由がわかりません。

このコマンド出力が与えられた場合:(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

オリジナルのコマンド置換が機能することを望んでいます。最初にフィールド区切り文字を設定する必要があるのか​​、それとも他に何が欠けているのか疑問に思います。何が行動の違いを引き起こすのかを理解しようとしています。

4
Philip Sweany
_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=(…)では、等号の直後に期待されるのはコマンドではなく、割り当ての値です。このコンテキストでは、括弧は値が配列であることを示します。

var=( some things )の括弧はサブシェルをマークせず、 配列割り当て構文 の一部です。したがって、それらがないと、通常の(スカラー)変数に割り当てることになります。通常の割り当ての右側は単語分割を通過しないため、var=$(echo foo bar)は文字列_foo bar_をvarにスペースを入れて配置します。一方、配列の割り当てには複数の単語が必要なため、arr=(foo bar)arr=( $(echo foo bar) )の両方で2要素の配列が得られます。

2
ilkkachu
_float=$( openstack floating ip list -c 'Floating IP Address' -f value )
_

これは コマンド置換通常の変数割り当て 内であり、配列割り当てではありません。 以下で使用するように、すべての複合配列の割り当てはx=( ... ) の形式になります。ここにはサブシェルはありません(置換されたコマンドの実行コンテキストとしての簡単な場合を除く)。

コマンド置換を使用すると、それらの内容がその位置にある変数と同じように動作するため、ここでは_float=$x_と同様に動作しますが、_ls $x_またはfoo=($x)でも動作します。 。 単語分割 は、展開の結果に対して実行されます。これにより、IFS変数の任意の文字で値が個別の引数に分割されます。

展開"$(...)"を引用することにより、単語の分割を抑制することができます。

分割された単語の配列を作成する場合は、配列を作成して単語を分割するためにbothが必要です。つまり、配列の割り当てfoo=(...)と、2番目の場合のように、パラメーターまたはコマンド置換_$..._を組み合わせます。

_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の項目として使用されます。

2
Michael Homer