Io-Redirection
重定向stdout和stderr時如何保持輸出順序?
為了描述這個問題,我創建了一個簡單的 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都重定向到同一個文件時如何保持輸出順序?
這是因為程序中的緩衝(在 C 庫中)。預設行為是,如果輸出到終端,輸出到 stdout 是行緩衝的,但如果輸出到文件則完全緩衝。預設情況下,stderr 始終是無緩衝的。
因此,由於您要列印整行,因此行緩衝並不明顯,但是當重定向到文件時,進入標準輸出的輸出會被緩衝,直到收集到整個塊(幾 kB),然後才實際寫入。(您也可以嘗試看看如果列印部分行會發生什麼。)
setbuf()
您可以使用/更改 C 程序內部的緩衝行為setvbuf()
,並使用該stdbuf
工具從外部更改(以及其他一些工具,請在站點上查找管道緩衝)。例如
setbuf(stdout, NULL)
,在程序開頭添加會使 stdout 無緩衝,並且執行它stdbuf -o0 ./a.out
也會這樣做。但這會減慢程序的速度。請注意,在您的最後一個範例中
cat <(./a.out)
,它只是通過的程序的標準輸出cat
,它的標準錯誤直接進入終端。如果兩者去不同的地方,通過另一個過程,就會導致重新排序。你需要cat <(./a.out 2>&1)
,或者./a.out 2>&1 | cat
讓他們都通過cat
。