Io-Redirection

重定向stdout和stderr時如何保持輸出順序?

  • May 9, 2022

為了描述這個問題,我創建了一個簡單的 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

引用自:https://unix.stackexchange.com/questions/701894