シェル スクリプトの場合と同じように、stdout を 1 つのファイルに保存し、stderr を別のファイルに保存し、stdout + stderr を 3 番目のファイルに保存し、さらに stdout + stderr をターミナルに取得するにはどうすればよいでしょうか。
私はこれを別の場所で見つけました:
exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out
非常に近いです。実行すると動作しbash test.sh 2>&1 | tee output
ますが、スクリプトの実行方法にアクセスできません。これは cicd システムです。exec を使用してスクリプト内から「結合出力」を実行できるようにする必要があります。
CI/CD ライブラリを作成していますが、クライアントがライブラリを何に使用するかがわからないため、各ユースケースを考慮に入れたいと思います。
答え1
アプローチを単純に拡張する:
exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)
標準エラーは という名前のファイルに書き込まれstderr
、標準出力は に書き込まれ、標準エラーと標準出力の両方がコンソール(またはの実行stdout
時に 2 つのファイル記述子が指しているもの)と に書き込まれます。 が書き込みを開始する2 番目のファイルによって上書きされないようにするには、 (追加) が必要です。exec
stdall
tee -a
stdall
tee
ご了承くださいオーダーリダイレクトが実行される場所は関係があります。2 番目のプロセス置換は最初のリダイレクトの影響を受けます。つまり、それが発行したエラーは に送信されます>(tee -a stderr stdall)
。もちろん、この副作用を回避するために、2 番目のプロセス置換の標準エラーを にリダイレクトすることができます。標準出力を標準エラーの前にリダイレクトすると、すべてのエラーが/dev/null
にも送信されます。stdout
stdall
Bashのプロセス置換のコマンドは実行されるので非同期的に、出力が生成された順序で表示されることを保証する方法はありません。さらに悪いことに、標準出力と標準エラーからのフラグメントが同じ行に表示される可能性が高くなります。
答え2
スクリプトは、IMLE が気まぐれで信頼性の低い$0
bash の構造に頼る代わりに、(無限再帰を避けるために環境変数を設定してチェックすることで) を介して完全に実行できます。> >(...)
if [ "$REDIRECTED" != 1 ]; then
export REDIRECTED=1
set -o pipefail
{ { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
exit
fi
# rest of your script here
は行バッファリングを使用しないためtee
( で強制することもできませんstdbuf(1)
)、stdout と stderr に書き込まれるデータの順序は最終出力では考慮されません。フルバッファリングを使用し、stdout と stderr の両方に書き込むコマンドでは、行バッファリングでもtee
役に立たず、さらに悪いことに、出力行の半分が stdout、半分が stderr になることがあります。
シェル言語とすぐに利用できるコマンドラインユーティリティだけを使用してこれを修正することはできないと思います。
答え3
CI/CD ライブラリを作成していますが、クライアントがライブラリを何に使用するかがわからないため、各ユースケースを考慮に入れたいと思います。
このようなシナリオを考えると、出力を処理するために bash が必要であるかどうか疑問に思います。理想的には、このコンテキストでは、出力にタイムスタンプを付け、標準出力タイプの ID を与え、アプリケーションがメッセージの処理方法を決定する必要があります。