在模仿 MacOS 终端的open
命令或 Window 终端的命令时start
,注释这个答案建议将 stdout 和 stderr 附加到~/.xsession-errors
,例如 ( bash
):
alias open='&>>~/.xsession-errors xdg-open'
我预见到的问题是竞争条件。lsof ~/.xsession-errors
显示有 22 个进程打开文件进行写入。
如何防止两个进程写入相同的偏移量~/.xsession-errors
?
答案1
当以追加模式打开文件时,操作系统保证所有写入都发生在末尾。因此,来自一个写入器的数据不会覆盖来自另一写入器的数据。
>>
这只适用于以追加模式(即在 shell 中)打开文件的情况。如果文件的创建者使用以下命令打开它,>
则该保证将不适用,并且可能具有以下顺序:
- 过程1
>out
:;现在在位置 0 - 过程2
>>out
:;现在在位置 0 - 进程 1:写入
hello
,现在位于位置 6 - 进程 2: write
world
,这被写入位置 6,进程 2 现在位于位置 12 - 进程1: write
oops
,这是在位置6写入的,因为进程1的文件位置没有改变。
在 Debian 上(自 2001 年左右),该文件.xsession-errors
由 `/etc/X11/Xsession 创建,并以追加模式打开,因此一切正常:
exec >>"$ERRFILE" 2>&1
我不知道登录到~/.xsession-errors
.
只要每个人都以附加模式打开文件,所有输出都会出现。然而,输出可能是碎片化的。实际上,对常规文件的足够小的写入是原子的。任何小于 512B 的东西在任何地方都应该足够小,而且我认为 Linux 保证的不仅仅是这个。因此,即使有多个并发编写器,每个日志行也应该显示完整,假设编写器使用行缓冲输出并且行不是太长。
1请注意,POSIX 不保证除管道之外的任何内容。
答案2
使用>>
在POSIX shell 保证文件将被打开O_APPEND
。
如果
O_APPEND
设置了文件状态标志的标志,则在每次写入之前应将文件偏移量设置为文件末尾,并且在更改文件偏移量和写入操作之间不应发生中间文件修改操作。
POSIX 定义了可以的最小字节数要求的写在一个单一的write(2)
称呼 (SSIZE_MAX
= 32,767)。返回值是实际写入的字节数(保证原子性)。
然而
并非所有文件系统都符合。从多个进程追加到文件说:
需要注意的是,并非所有文件系统都兼容 POSIX。两个著名的例子是 NFS 和 Hadoop 分布式文件系统 (HDFS)。在这些网络文件系统上,追加是模拟的并且受到竞争条件的影响。
不是每个人都玩得好
虽然您可以使用 打开O_APPEND
,但写入该文件的其他进程可能不会。您可以检查任何给定的文件:
lsof +fg <file>
令人担忧的是,当我跑步时lsof +fg ~/.xsession-errors
,我看到不 AP
(append) 标志,表明我的列表中的 22 个进程(基于 Arch 的 Manjaro Linux)没有安全地打开文件。
仅当我cat >> ~/.xsession-errors
在另一个 shell 中运行时,最终输出行才会包含该AP
标志:
cat 3099 ravi 1w REG W,AP,LG 0,48 963 1926479 .xsession-errors
如果有人知道应该在上游哪里提出这个问题,请发表评论。
几乎
如果所有进程都使用以下任一方式在本地打开文件:
open(2)
和旗帜O_APPEND
fopen(3)
和"a"
旗帜- POSIX
sh
>>
或者bash
&>>
那么任何数据都不应该通过竞争条件被覆盖。
谢谢@吉尔斯回答为我指明了正确的方向。