次のシェルスクリプト関数を考えてみましょう。
#!/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\
になります。D
E/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