bash中stdout和stderr的顺序

scr*_*apy 2 bash redirect

ls test.mp4  test.sh 1>/tmp/text  2>&1
cat   /tmp/text
ls: cannot access test.sh: No such file or directory
test.mp4
Run Code Online (Sandbox Code Playgroud)

为什么结果不是以下顺序?

test.mp4
ls: cannot access test.sh: No such file or directory
Run Code Online (Sandbox Code Playgroud)

也许1>/tmp/text先执行,然后在test.sh之前找到test.mp4。
效果如何?

ric*_*ici 5

这与bash无关。它只是反映了C标准库I / O函数缓冲输出的方式。

man setvbuf是Linux系统上的有用摘录(解释大部分来自C和Posix标准,但我认为在此摘录中很容易找到和理解)。第二段是您看到的行为的说明。

可用的三种缓冲类型是非缓冲,块缓冲和行缓冲。当输出流未缓冲时,信息将在写入后立即出现在目标文件或终端上。当它被块缓冲时,许多字符被保存起来并写成一个块;当是行缓冲字符时,将保存这些字符,直到从连接到终端设备的任何流(通常为stdin)输出换行或读取输入为止。fflush(3)函数可用于强制将块提前退出。(请参阅fclose(3)。)

通常,所有文件都是块缓冲的。如果流引用终端(如stdout通常所做的那样),则会对其进行行缓冲。默认情况下,标准错误流stderr始终未缓冲。

因此,回顾一下。stdout通常指的是终端,因此是行缓冲的,但是您已将其重定向到文件,以便对其进行块缓冲。但是,stderr无论是否已重定向,始终处于无缓冲状态。

因此,所有打印到的stderr内容stdout都会立即显示,而打印到的内容将保留到缓冲区填满为止(在Linux上,通常为8kb)。

请注意,当ls检测到stdout不是终端时,-1默认情况下会设置标志(每行一个文件名)。否则,它将-x默认设置该标志(文件名与一行中的文件名一样多)。这意味着您将在终端上看到相同的反转,而无需任何重定向:

$ ls good bad
ls: cannot access bad: No such file or directory
good
Run Code Online (Sandbox Code Playgroud)