プロセス置換、、を適切に使用して、一時ファイルなしで(配管が好きな場合)、2つの別々の変数stderr
をキャプチャする非常に醜い方法があります。私はあなたのコマンドを呼び出します。次の関数を使用して、このようなコマンドを模倣できます。stdout
source
declare
banana
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
}
banana
in変数の標準出力と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はbanana
stdoutを介して端末に表示されます(リダイレクトのおかげで)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
のコンテンツを表示します。berr
declare
この時点で、端末画面に次のように表示されます。
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
、常に適切にエスケープされるからです。
もちろん、出力を配列に入れたい場合(たとえば、mapfile
Bash≥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)