use*_*539 4 ls bash debian io-redirection
我有一个文件test.txt,但没有名为test. 当我尝试
ls test test.txt > new 2>new
Run Code Online (Sandbox Code Playgroud)
我期待new被覆盖,因为>>没有使用。但是在输出文件中,我附加了两个内容。为什么会这样?
TL;DR bash在写入任何内容之前打开并截断所有涉及的文件。stdout并且stderr都被发送到new因为bash在ls开始打印时已经截断了文件(两次)。
这就是bash准备/处理 I/O 重定向的方式。当您要求将命令重定向 ( >) 到文件时,bash基本上会打开该文件,并在必要时创建它。如果文件已存在,则将其截断。这是通过open系统调用和一些标志完成的,在您的情况下:
open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666)
Run Code Online (Sandbox Code Playgroud)
O_CREAT如果文件不存在,则创建该文件,而O_TRUNC当它存在时截断它。此open系统调用是bash重定向初始化的一部分,这意味着当您使用多个重定向操作时,例如在...
$ ls test test.txt > new 2>new
Run Code Online (Sandbox Code Playgroud)
...bash首先打开所有相关文件。因此,在运行之前ls,它new使用相同的标志打开两次:
open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666)
open("new", O_WRONLY|O_CREAT|O_TRUNC, 0666)
Run Code Online (Sandbox Code Playgroud)
这意味着基本上,在运行您的命令时,bash会执行以下操作(按该顺序):
new作为标准输出打开,必要时创建/截断文件。new作为标准错误打开,必要时创建/截断文件。ls:这会将内容写入new.如您所见,在开始之前bash截断所有涉及的文件。这意味着当使用,运行某些东西时,基本上被“两次”截断,然后,输出被重定向到它。您期望的行为需要独立捕获的 stdout 和 stderr,并在写入之前一个接一个地打开它们。基本上:ls... >new 2>newnewbashls
ls。stdout,打开new,截断它并写入它。stderr,new再次打开,截断它,然后写入。但是,消息可能会交织在一起:重定向的程序很可能会向 写入一些内容stdout,然后向 写入其他内容stderr,然后返回stdout......管理所有这些会很糟糕(并且可能导致不受欢迎的(未定义?)行为……)。