目标文件尚不存在时,使用`>>`重定向是否等同于`>`?


80

考虑像Bash或sh这样的shell。在目标文件存在的情况下,>和之间的基本区别在于>>

  • > 将文件截断为零大小,然后写入;
  • >> 不截断,它写入(附加)到文件的末尾。

如果文件不存在,则会以零大小创建文件;然后写。对于两个运营商都是如此。当目标文件尚不存在时,这些运算符似乎等效。

是真的吗

Answers:


107

tl; dr

编号>>本质上是“始终寻求文件结尾”,同时>保持指向最后写入位置的指针。


完整答案

(注意:我所有的测试都是在Debian GNU / Linux 9上完成的)。

另一个不同

不,它们不是等效的。还有另一个区别。无论目标文件之前是否存在,它都可能显示出来。

要观察它,请运行一个生成数据的过程,然后使用>>>(例如pv -L 10k /dev/urandom > blob)将其重定向到文件。让它运行并更改文件的大小(例如,使用truncate)。您将看到>其偏移量(不断增加),而>>始终附加到末尾。

  • 如果将文件截断为较小的大小(可以为零)
    • >不在乎,它将以所需的偏移量写入,好像什么也没发生;截断偏移量刚好超出文件末尾之后,这将导致文件重新获得其旧大小并进一步增长,丢失的数据将填充零(如果可能的话,采用稀疏方式);
    • >> 将追加到新的末尾,文件将从其截断的大小开始增长。
  • 如果放大文件
    • >不在乎,它将以所需的偏移量写入,好像什么也没发生;更改大小后,偏移量刚好在文件内的某个位置,这将导致文件停止增长一段时间,直到偏移量达到新的末端为止,然后文件将正常增长;
    • >> 将添加到新的末尾,文件将从其放大的大小开始增长。

另一个示例是>>在数据生成过程正在运行并写入文件时,附加一些内容(带有单独的)。这类似于放大文件。

  • 生成过程>将以其所需的偏移量写入并最终覆盖多余的数据。
  • 生成过程>>将跳过新数据并追加到新数据之后(竞争条件可能会发生,两个流可能会交错,但仍然不应覆盖任何数据)。

在实践中有关系吗?有这个问题

我正在运行一个在stdout上产生大量输出的进程。将其全部发送到文件[...]我可以使用某种日志轮换程序吗?

这个答案说解决方案是logrotate带有如下copytruncate选项的选项:

创建副本后,将原日志文件截断到位,而不是移动旧日志文件并选择创建新的日志文件。

根据我在上面写的内容,使用重定向>将立即使截断的日志变大。稀疏性可以节省一天的时间,不应浪费大量的磁盘空间。但是,每个连续的日志中将有越来越多的前导零,这是完全没有必要的。

但是,如果logrotate创建副本时不保留稀疏性,则每次创建副本时,这些前导零将需要越来越多的磁盘空间。我还没有研究过工具的行为,它在稀疏或动态压缩的情况下(如果启用了压缩)可能足够聪明。零仍然可能只会造成麻烦或充其量是中立的。他们没有什么好。

在这种情况下,即使将要创建目标文件,使用>>代替>也会更好。


性能

如我们所见,这两个运算符不仅在开始时表现不同,而且在以后表现不同。这可能会导致一些(微妙的)性能差异。目前,我没有有意义的测试结果来支持或反对它,但是我认为您不应该自动假定它们的性能大致相同。


9
因此>>,在>保持指向最后写入位置的指针的同时,本质上是“始终寻求文件结尾” 。似乎有可能是他们的工作以及方式有些细微的性能差异...
Mokubai

10
在系统调用级别,>>O_APPEND标志用于open()。实际上,>使用O_TRUNC,而>>没有使用。的组合O_TRUNC | O_APPEND也是可能的,shell语言只是不提供该功能。
ilkkachu

3
@jjmontes,标准来源为POSIX:pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/…但是,当然,Bash的手册中也有关于重定向操作符的说明,包括它支持的非标准操作符:gnu.org/ software / bash / manual / html_node / Redirections.html
ilkkachu,

2
@ilkkachu我发现这很有趣,因为它解释了有关O_APPEND的详细信息,我在您的评论后一直在想:):stackoverflow.com/questions/1154446/…–
jjmontes

1
@Mokubai,任何理智的操作系统在打开时都会拥有文件长度,并且检查标记并将偏移量移到最后应在所有其他簿记中都消失了。试图仿效O_APPENDlseek()各前write()会有所不同,虽然有会是额外的系统调用的开销。(当然,这是行不通的,因为可能会write()在另一个过程之间进行。)
ilkkachu
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.