重定向 stdout 和 stderr 时如何保持输出顺序?

重定向 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 重定向到同一文件时如何保持输出顺序?

答案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

相关内容