この問題を説明するために、単純なCプログラムを作成しました。
root@u2004:~# cat test.c
#include <stdio.h>
int main(){
printf("output 1\n");
fprintf(stderr, "error 1\n");
printf("output 2\n");
fprintf(stderr, "error 2\n");
return 0;
}
root@u2004:~# gcc test.c
root@u2004:~#
実行すると、次の結果が表示されます。
root@u2004:~# ./a.out
output 1
error 1
output 2
error 2
root@u2004:~#
ご覧のとおり、コンソールの出力順序はプログラムで定義されているステートメントと同じです。今私はstderrとstdoutを単一のファイルにリダイレクトし、出力順序を維持したいと思います。私が試したことは次のとおりです。
root@u2004:~# ./a.out > out 2>&1
root@u2004:~# cat out
error 1
error 2
output 1
output 2
root@u2004:~#
root@u2004:~# cat <(./a.out)
error 1
error 2
output 1
output 2
root@u2004:~#
ご覧のとおり、どちらの場合も最初にエラーメッセージが表示され、通常の出力が表示されます。これはプログラムで定義した順序とは異なります。 stdoutとstderrを同じファイルにリダイレクトするときに出力順序を維持する方法は?
答え1
これは、プログラム(Cライブラリ)のバッファリングによるものです。デフォルトの動作は、stdoutへの出力が端末に移動するとラインバッファリングされますが、ファイルに移動すると完全にバッファリングされます。デフォルトでは、stderrは常にバッファリングされません。
したがって、ライン全体を印刷するため、ラインバッファリングは明確ではありませんが、ファイルにリダイレクトされると、stdoutに送信された出力は、実際に作成される前にチャンク全体(数kB)が収集されるまでバッファリングされます。 (行の一部を印刷すると、何が起こるかを確認することもできます。)
setbuf()
Cプログラム内でバッファリング動作を有効/変更することができ、setvbuf()
このツールを使用して外部でバッファリング動作を変更できますstdbuf
(他のツールもたくさんあるので、サイトでパイプバッファリングを見つけてください)。
setbuf(stdout, NULL)
たとえば、プログラムの先頭に追加すると、標準出力はバッファリングされず、実行してもstdbuf -o0 ./a.out
同じです。ただし、これによりプログラムが遅くなります。
最後の例では、cat <(./a.out)
プログラムの標準出力のみを通過し、cat
標準エラーは端末に直接渡されます。二人が別の場所に行って別の過程を経ると、並べ替えが発生する。あなたはそれをすべて渡さcat <(./a.out 2>&1)
なければなりません。./a.out 2>&1 | cat
cat