在Linux上使用“ >>”时,bash是否会在O_APPEND中打开文件?


38

如果使用,echo 1234 >> some-file则说明文档将附加输出。

我的猜测是,如果某些文件不存在,则O_CREAT将创建一个新文件。如果>已使用,则O_TRUNC将截断现有文件。

在以下情况下>>:是否将文件以O_WRONLY(或O_RDWR)打开并试图结束并模拟O_APPEND来完成写入操作?还是将文件以O_APPEND的形式打开,然后将其留在内核中以确保追加?

我之所以这样问是因为,当输出文件来自NFS挂载点时,conserver进程会覆盖通过echo插入的一些标记,并且NFS Documentation说服务器上不支持O_APPEND,因此客户端内核将不得不处理它。我猜服务器进程正在使用O_APPEND,但是不确定>>Linux上的bash ,因此在这里提出问题。


12
O_APPEND不支持NFS上的问题;问题是它是模拟的。在本地文件系统上,写入打开相同文件的多个进程O_APPEND 将永远不会覆盖彼此的数据。在NFS上,O_APPEND通过在写入之前先查找到结尾来进行仿真,从而保留了竞争条件的可能性。在NFS上无法解决此问题。每个并行编写器都需要编写自己的文件。解决此问题的唯一方法是在NFS服务器上设置服务器进程,使记录器记录到|nc server port,并使服务器将传入数据附加到日志中。
Guntram Blohm

@ GuntramBlohm,+ 1,感谢您的确认。基本上,您的建议是仅对文件使用一个编写器进程,所有其他编写器进程都将通过此进程。
2015年

这么多好的答案,不确定我应该接受哪个答案。首先,Bruce Ediger显示使用了O_APPEND。接下来的Random832表明,这是在标准中给出的。最后,埃里克·雷诺夫(Eric Renouf)展示了具有相同答案的源代码。所有这三个观点共同构成了最终的完整画面。
2015年

6
简而言之,NFS包含大量错误,因此不应使用。
R ..

2
是的,但是我们早在发明O_EXCL时就已经学过了。
凯文

Answers:


60

我执行此操作:strace -o spork.out bash -c "echo 1234 >> some-file"找出您的问题。这是我发现的:

open("some-file", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

我运行echo命令的目录中没有名为“ some-file”的文件。


50

这不仅在Bash中完成,而且是标准要求的。

从单一Unix规范

附加的输出重定向将导致其名称由单词扩展产生的文件打开,以在指定的文件描述符上输出。如同使用O_APPEND标志调用了POSIX.1-2008的系统接口卷中定义的open()函数一样,打开了该文件。如果文件不存在,则应创建它。

因此,任何符合POSIX的外壳都必须这样做。在某些Unix系统上,/bin/sh可能是非POSIX Bourne外壳程序(Bourne外壳程序最初是在O_APPEND发明之前编写的),并且可用的POSIX外壳程序通常是ksh,可以sh在其他路径位置(例如Solaris的位置)使用/usr/xpg4/bin


2
有趣的是,一个不这样做的外壳是Bourne外壳。Bourne Shell将打开,而没有O_TRUNC和lseek()到最后。那是因为它是在O_APPEND标志添加到之前写入的open()>>本身是由其前身Thomson Shell引入的。
斯特凡Chazelas

1
@StéphaneChazelas另外,我还在各种版本的C shell源代码中查找,直到4.3BSD-Reno才引入O_APPEND标志。
Random832

它说“好像”,难道不能以不同的方式实现(但产生相同的可观察效果)吗?似乎该标准不需要使用O_APPEND,而只是表现得“好像”。
汤玛斯(Thomas)

1
@Thomas这确实意味着您将获得O_APPEND记录的所有行为,这意味着在每次写操作后都要重新定位。“好像”只是标准语言,旨在允许通过某种方式(例如,在非传统Unix平台上实际调用open()函数以外的方式)将其打开。
Random832

+1,用于表明此行为符合标准。
2015年

32

在源代码中查找,它确实使用O_APPEND。对于710-713 make_cmd.c行中的bash 4.3.30,请阅读:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;

+1,用于从源代码角度显示答案。
2015年

19

让我们研究一下strace在本地(非NFS)文件系统上的使用:

$ strace -eopen -- bash -c "echo foo >> /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

$ strace -eopen -- bash -c "echo foo > /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

其他炮弹,即dashdashsh的busybox的”和mksh行为方式相同。

该选项-e open意味着-e trace=open仅跟踪open()系统调用。

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.