シェルスクリプトのようにstdoutをあるファイルに、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
機能しますが、スクリプトの実行方法にアクセスできません。これはCIDシステムです。 execを使用してスクリプト内で「結合出力」を実行できる必要があります。
CI / CDライブラリを作成していますが、顧客がライブラリをどのように使用するのかわからないので、すべてのユースケースを検討したいと思います。
答え1
簡単に方法を拡張してください。
exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)
stderrはstdoutというファイルに書き込まれstderr
、stderrstdout
とstdoutはコンソール(またはexec
実行時に2つのファイル記述子が指すすべてのエントリ)とstdoutにも書き込まれますstdall
。 (追加)は、書き込みを開始する2番目のデータが上書きされるのを
tee -a
防ぐために必要です。stdall
tee
気づく注文するリダイレクトを実行することが関連しています。 2番目のプロセスの交換は、最初のリダイレクトの影響を受けます。つまり、発生したエラーはに送信されます>(tee -a stderr stdall)
。もちろん、/dev/null
これらの副作用を避けるために、2番目のプロセス交換の標準エラーをリダイレクトできます。標準エラーの前に標準出力をリダイレクトすると、すべてのエラーがstdout
およびに送信されますstdall
。
Bash プロセス置換コマンドが実行されるため非同期的、生成された順序で出力が表示されるという保証はありません。さらに悪いことは、標準出力と標準エラーの断片が同じ行に現れることです。
答え2
$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
。
私はこの問題がシェル言語とあらかじめ作成されたコマンドラインユーティリティだけでは解決できないと思います。
答え3
CI / CDライブラリを作成していますが、顧客がライブラリをどのように使用するのかわからないので、すべてのユースケースを検討したいと思います。
このような状況を考えると、bashが出力を処理する必要があるかどうか疑問に思われます。この場合、理想的には、出力にタイムスタンプを付けて標準出力タイプのIDを提供する場合は、アプリケーションがメッセージで何をするかを決定する必要があります。