考虑像 Bash 或 sh 这样的 shell。>
和之间的基本区别>>
体现在目标文件存在的情况下:
>
将文件截断为零大小,然后写入;>>
不会截断,它会写入(附加)到文件末尾。
如果文件不存在,则创建文件并将其大小设为零,然后写入。对于这两个运算符来说都是如此。当目标文件尚不存在时,这两个运算符似乎是等效的。
真的是这样吗?
答案1
总结
本质>>
上是“始终寻找文件末尾”,同时>
保持指向最后写入位置的指针。
完整答案
(注意:我所有的测试都是在 Debian GNU/Linux 9 上完成的)。
另一个区别
不,它们不等同。其他差异。无论目标文件之前是否存在,它都可能表现出来。
>
为了观察它,运行一个生成数据并重定向到带有或 的文件的进程>>
(例如pv -L 10k /dev/urandom > blob
)。让它运行并更改文件的大小(例如truncate
)。您将看到>
保持其(不断增长的)偏移量,而>>
始终附加到末尾。
- 如果将文件截断为较小的尺寸(可以是零尺寸)
>
不会在意,它会像什么都没发生一样在其所需的偏移量处写入;截断后偏移量超出了文件的末尾,这将导致文件恢复其旧大小并进一步增长,丢失的数据将用零填充(如果可能的话,以稀疏的方式);>>
将附加到新的末尾,文件将从其截断的大小开始增长。
- 如果你放大文件
>
不会在意,它会像什么都没发生一样在其所需的偏移量处写入;只需改变文件大小后偏移量就在文件内部的某个地方,这将导致文件停止增长一段时间,直到偏移量到达新的末尾,然后文件就会正常增长;>>
将附加到新的末尾,文件将从其扩大的大小开始增长。
另一个示例是在数据生成过程运行并写入文件时附加(使用单独的>>
)一些额外内容。这类似于扩大文件。
- 生成过程
>
将在其所需的偏移量处写入并最终覆盖多余的数据。 - 生成过程
>>
将跳过新数据并将其附加到后面(可能会发生竞争条件,两个流可能会交错,但仍然不会覆盖任何数据)。
例子
在实践中这有关系吗?这个问题:
我正在运行一个在 stdout 上产生大量输出的进程。将其全部发送到文件 [...] 我可以使用某种日志轮换程序吗?
这个答案说解决方案是logrotate
使用copytruncate
如下选项:
创建副本后截断原始日志文件,而不是移动旧日志文件并选择性地创建新日志文件。
根据我上面所写,重定向>
将立即使截断的日志变大。稀疏性将挽救局面,不会浪费大量磁盘空间。然而,每个连续的日志中将有越来越多的前导零,而这些零是完全不必要的。
但是,如果logrotate
创建副本时不保留稀疏性,那么每次复制时这些前导零将需要越来越多的磁盘空间。我还没有调查过该工具的行为,它可能足够智能,可以动态处理稀疏性或压缩(如果启用了压缩)。然而,这些零可能只会造成麻烦,或者充其量是中性的;它们没有什么好处。
在这种情况下,使用>>
而不是>
会更好得多,即使目标文件即将被创建。
表现
我们可以看到,这两个操作符不仅在开始时表现不同,而且在之后也不同。这可能会导致一些(微妙的?)性能差异。目前我没有有意义的测试结果来支持或反驳这一点,但我认为你不应该自动假设它们的性能总体上是相同的。