为什么“命令1> file.txt 2> file.txt”的行为与“命令1> file.txt 2>&1”不同?


20

当您要将stdout和stderr都重定向到同一文件时,可以使用command 1>file.txt 2>&1或来实现command &>file.txt。但是,为什么行为command 1>file.txt 2>file.txt与以上两个命令不同?

以下是验证命令。

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

从结果看,看起来第二个回显字符串在运行时会覆盖第一个回显字符串command 1>file.txt 2>file.txt,但我不知道为什么会这样。(在某处有参考吗?)

Answers:


43

您需要知道两件事:

  • 进程的应用程序模式端已知的打开文件描述符引用了称为文件描述的内部内核对象,该文件描述是打开文件的实例。每个文件可以有多个文件描述,并且多个文件描述符共享一个文件描述。
  • 当前文件位置是一个的属性文件描述。因此,如果多个文件描述符映射到单个文件描述,则它们都共享相同的当前文件位置,并且使用一个这样的文件描述符对文件位置进行的更改会影响所有其他这样的文件描述符。

    这样的变化是通过调用过程颁布read()/ readv()write()/ writev()lseek()和诸如此类的系统调用。该echo命令当然会调用write()/ writev()

那么会发生什么:

  • command 1>file.txt 2>&1仅创建一个文件描述,因为外壳仅打开一个文件一次。壳品牌二者的标准输出和标准误差文件描述符映射到单个文件说明。它将标准输出复制到标准错误上。因此,通过任何一个文件描述符进行的写操作都将移动共享的当前文件位置:每次写操作都在前一个写操作之后的通用文件描述之后进行。如您所见,echo命令的结果不会相互覆盖。
  • command 1>file.txt 2>file.txt之所以创建两个文件描述,是因为shell响应两次显式重定向将同一个文件打开了两次。标准输出和标准错误文件描述符映射到两个不同的文件描述,然后依次映射到同一单个文件。这两个文件描述具有完全独立的当前文件位置,并且每次写操作都会立即在同一文件描述上进行前一次写操作。正如您所看到的那样,根据执行写入的顺序,通过一种方式写入的内容可以以各种不同的方式覆盖通过另一方写入的内容。

进一步阅读


1
应该是打开的文件描述,而不是文件描述。与文件本身有关的更多信息是文件的打开方式。至少这是POSIX,Linux,Solaris和GNU文档使用的术语。
斯特凡Chazelas

16

使用>告诉它覆盖文件。由于您已通过两种不同的操作将stdout和stderr写入文件,因此要写入的最后一个将覆盖第一个。

你可以做:

command 1>>file.txt 2>>file.txt

要么

command &>file.txt 仅bash v4及更高版本。

>> 告诉它附加文件,以便它不会替换先前操作的输出。

&> 只是一种更简单的书写方式 2>&1


2
为什么ls 1>&0ls 0>&0仍然显示LS的输出?
伊万2015年

我对使用>>作品感到惊讶。为什么这没有两个具有独立偏移量的文件描述的问题?@JdeBP,你知道吗?我认为以追加模式打开文件等同于以写入模式打开文件,然后寻找到最终位置,然后不允许进一步寻找。
JoL

4
@jlmg:可以搜索追加模式文件,但是每次写入都以隐含的结尾作为前缀。对我而言,这种隐含的寻求是否是原子性的尚不清楚。
凯文(Kevin)2009年

1
这完全取决于后续问题。与此相关的这样的人表示答案不完整。人们不太可能在不希望知道完整答案的情况下查找后续问题。因此,此类后续问题很有可能会得到重复信息的答案,从而成为重复信息。
2015年

1
@Kevin,在完全符合POSIX的文件系统上,隐式O_APPEND查找是原子的。也就是说,并非每个文件系统都正确实现了相关的语义-例如,NFS(至少在v3和以前的版本中-我不清楚在v4上)并没有在有线协议中引入相关的支持,因此服务器具有无法知道客户端是否使用打开了文件O_APPEND
Charles Duffy
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.