私はこの構文を知っています
var=`myscript.sh`
または
var=$(myscript.sh)
myscript.sh
の結果(stdout
)をvar
にキャプチャします。両方をキャプチャする場合は、stderr
をstdout
にリダイレクトできます。それぞれを別々の変数に保存する方法は?
ここでの私の使用例は、戻りコードがゼロ以外の場合、stderr
をエコーし、それ以外の場合は抑制したい場合です。これを行う方法は他にもありますが、実際に可能であれば、このアプローチはうまくいくようです。
一時ファイルなしで両方をキャプチャする方法はありません。
Stderrを変数にキャプチャし、stdoutをユーザー画面に渡すことができます( here のサンプル):
exec 3>&1 # Save the place that stdout (1) points to.
output=$(command 2>&1 1>&3) # Run command. stderr is captured.
exec 3>&- # Close FD #3.
# Or this alternative, which captures stderr, letting stdout through:
{ output=$(command 2>&1 1>&3-) ;} 3>&1
ただし、stdoutとstderrの両方をキャプチャする方法はありません。
できないのは、FDリダイレクトのみを使用して、1つの変数にstdoutをキャプチャし、別の変数にstderrをキャプチャすることです。あなたはmust一時ファイル(または名前付きパイプ)を使用してそれを実現する必要があります。
プロセス置換 、stderr
、およびを使用して、一時ファイルなしで(配管が好きな場合)stdout
およびsource
を2つの別々の変数にキャプチャする本当にreallyい方法があります_ [変数] _適切。コマンドdeclare
を呼び出します。次の関数を使用して、このようなコマンドを模倣できます。
banana() {
echo "banana to stdout"
echo >&2 "banana to stderr"
}
変数banana
のbanana
の標準出力と、変数bout
のbanana
の標準エラーが必要であると仮定します。これを実現する魔法を以下に示します(Bash≥4のみ):
. <({ berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr; } 2>&1)
それで、ここで何が起こっているのでしょうか?
最も内側の用語から始めましょう。
bout=$(banana)
これは、端末に表示される標準エラーであるberr
の標準出力をbout
に割り当てる標準的な方法です。
次に:
{ bout=$(banana); } 2>&1
banana
のbout
にはまだbanana
のstdoutが割り当てられますが、banana
のstderrはstdout経由で端末に表示されます(リダイレクトのおかげで2>&1
。
次に:
{ bout=$(banana); } 2>&1; declare -p bout >&2
上記のようになりますが、bout
の内容をdeclare
ビルトインで端末に(stderr経由で)表示します:これはすぐに再利用されます。
次に:
berr=$({ bout=$(banana); } 2>&1; declare -p bout >&2); declare -p berr
berr
の標準エラーをbanana
に割り当て、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
前のものが標準出力経由で表示されます。
最後に、これらの行の内容を プロセス置換 からsourceに使用します。
コマンドの戻りコードについても言及しました。 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
ingまたはeval
ingのみがdeclare -p
から取得され、常に適切にエスケープされるため、これはすべて安全です。
もちろん、配列に出力が必要な場合(たとえば、mapfile
を使用する場合、Bash≥4を使用する場合は、mapfile
をwhile
–read
に置き換えます。ループ)、適応は簡単です。
例えば:
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)
できるよ:
OUT=$(myscript.sh 2> errFile)
ERR=$(<errFile)
今$OUT
はスクリプトの標準出力を持ち、$ERR
にはスクリプトのエラー出力があります。
簡単だがエレガントな方法:stderrを一時ファイルにリダイレクトし、それを読み返す:
TMP=$(mktemp)
var=$(myscript.sh 2> "$TMP")
err=$(cat "$TMP")
rm "$TMP"
Bashで変数を分離するためにstderrとstdoutをキャプチャする方法を見つけていませんが、両方を同じ変数に送信します…
result=$( { grep "JUNK" ./junk.txt; } 2>&1 )
…その後、終了ステータス「$?」を確認し、$ resultのデータを適切に処理します。