コマンド置換で配列に複数の値を割り当てる方法は?

コマンド置換で配列に複数の値を割り当てる方法は?

次のシェルスクリプト関数を考えてみましょう。

#!/bin/bash

declare -a dir

function() {
local -a directories=( "A/B/C D" "E/F G H" ) #Initialize local array.
printf "%q " "${directories[@]}"             #"Return" values of array in escaped form.
}

dir=( $(funcion) )

for i in "${dir[@]}"; do
  echo $i
done

コマンド置換がどのように機能するか:

dir=( A/B/C\ D E/F\ G\ H ) #Escape the whitespace.

スクリプトの結果は次のようになります。

A/B/C D
E/F G H

コマンドの置き換えが実際にどのように機能するか(結果のためにそう思います):

dir=( A/B/C\\ D E/F\\ G\\ H ) #Escape the backslash.

スクリプトの結果は次のとおりです。

A/B/C\
D
E/F\
G\
H

私のように動作させる方法はありませんか?

答え1

私の考えでは、あなたは\nこれprintfを持っています。

$ directories=( "A/B/C D" "E/F G H" )
$ printf "%q " "${directories[@]}"

これは以下を効果的に評価します。

$ printf "%q " "A/B/C D" "E/F G H"
A/B/C\ D E/F\ G\ H

これにより、forループが、、、およびを繰り返すことA/B/C\になります。DE/F\G\H

代わりに以下を使用する場合"%q\n":

$ printf "%q\n" "${directories[@]}"
A/B/C\ D
E/F\ G\ H

その後、次を使用して結果(から来ると仮定func)を配列として読み取ることができます。

readarray -t dir < <(func)

答え2

directories=( "A/B/C D" "E/F G H" ) #Initialize local array.
printf "%q " "${directories[@]}"

これにより、出力がシェル入力として使用するのに適しているように、引用された値が印刷されます。

dir=( $(func) )

その後、出力が得られfunc、トークン化およびワイルドカードを介して実行され、結果フィールドが配列に格納されます。

互換性のある形式ではありません。特に、後者は取得したデータを次のように処理します。データ、引用符、エスケープ、演算子などのシェル構文を解析しません。空白だけが見えます。 (データのバックスラッシュは外れません。当初は特別な意味はありません。)

入力をシェル構文として扱うには、を介して実行する必要がありますevalが、これは他のものも実行されるという欠点があります。たとえば、組み込みのコマンド置換が実行されます(考えてみてください$(reboot))。

より良いアプローチは、最初からデータをシェル構文に変換しないことです。代わりに、適切な文字を終端として使用して配列値を印刷し、プロセス置換をread使用してreadarray再読み込みします。

たとえば、改行区切り文字を使用すると、次のようになります。

f() {
    printf "%s\n" "hello world" 'some"quotes\etc'
}
readarray -t arr < <(f)

あるいは、NUL文字を区切り文字として使用して、値に改行文字を含めることもできます。

g() {
    printf "%s\0" "hello world" 'some"quotes\etc' $'two\nlines\n'
}
readarray -d '' -t arr < <(g)

(しかし、Bashにはキーワードがあるfunction() ...ので動作しませんが、DashとBusyboxでは動作しますが、配列では動作しません。)function

関連情報