プロセス置換、、を適切に使用して、一時ファイルなしで(配管が好きな場合)、2つの別々の変数stderrをキャプチャする非常に醜い方法があります。私はあなたのコマンドを呼び出します。次の関数を使用して、このようなコマンドを模倣できます。stdoutsourcedeclarebanana
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
}
bananain変数の標準出力とin変数boutの標準誤差が必要であると仮定bananaしますberr。これを実現する魔法は次のとおりです(Bash≥4のみ):
. <({ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
それで、ここで何が起こっているのですか?
最も内側の用語から始めましょう:
bout=$(banana)
boutこれは、の標準出力に割り当てる標準的な方法でbananaあり、標準エラーが端末に表示されます。
それで:
{ bout=$(banana); } 2>&1
は引き続きboutのstdoutに割り当てられますbananaが、のstderrはbananastdoutを介して端末に表示されます(リダイレクトのおかげで)2>&1。
それで:
{ bout=$(banana); } 2>&1; declare -p bout >&2
bout上記と同じように動作しますが、組み込みのコンテンツを(stderr経由で)端末に表示しますdeclare。これはまもなく再利用されます。
それで:
berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr
berrのstderrに割り当て、 withbananaのコンテンツを表示します。berrdeclare
この時点で、端末画面に次のように表示されます。
declare -- bout="banana to stdout"
declare -- berr="banana to stderr"
行で
declare -- bout="banana to stdout"
stderrを介して表示されます。
最終的なリダイレクト:
{ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1
stdoutを介して前のものが表示されます。
最後に、プロセス置換を使用して、これらの行のコンテンツを調達します。
コマンドの戻りコードについても言及されました。次のように変更bananaします。
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
return 42
}
また、次のようbananaに変数にの戻りコードがあります。bret
. <({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)
を使用することで、ソーシングやプロセス置換なしで実行できevalます(Bash <4でも機能します)。
eval "$({ berr=$({ bout=$(banana); bret=$?; } 2>&1; declare -p bout bret >&2); declare -p berr; } 2>&1)"
そして、これはすべて安全です。なぜなら、私たちが行っている、sourceまたは行っているものはeval、そこから取得されdeclare -p、常に適切にエスケープされるからです。
もちろん、出力を配列に入れたい場合(たとえば、mapfileBash≥4を使用している場合は– <code> readループに置き換えmapfileてwhileください)、適応は簡単です。
例えば:
banana() {
printf 'banana to stdout %d\n' {1..10}
echo >&2 'banana to stderr'
return 42
}
. <({ berr=$({ mapfile -t bout < <(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
戻りコード付き:
. <({ berr=$({ mapfile -t bout< <(banana; bret=$?; declare -p bret >&3); } 3>&2 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)