将输出重定向到文件是否会锁定文件?

30 shell bash io-redirection lock

如果我有命令

$ ./script >> file.log
Run Code Online (Sandbox Code Playgroud)

被调用两次,第二次调用发生在第一个结束之前,会发生什么?

第一次调用是否获得了输出文件的排他锁?如果是这样,第二个脚本是否在尝试写入时失败,或者 shell 是否接受输出(允许脚本结束)并抛出错误?

或者日志文件被写入两次?

Gil*_*il' 23

Unix 系统基本上避免强制锁。在少数情况下,内核会锁定文件以防止用户程序修改,但如果它只是由另一个程序编写,则不会。没有 unix 系统会因为程序正在写入文件而锁定文件。

如果您希望脚本的并发实例不会相互影响,则需要使用显式锁定机制,例如.flock lockfile

当你打开一个文件进行追加时,>>每个程序都保证总是写入文件的末尾。所以多个实例的输出永远不会相互覆盖,如果它们轮流写入,它们的输出将与写入的顺序相同。

可能发生的坏事是,如果其中一个实例写入多个输出块并期望它们一起出现。在一个实例连续写入之间,其他实例可以执行自己的写入。例如,如果实例 1 写入foo,然后实例 2 写入hello,然后实例 2 写入bar,则文件将包含foohellobar.

进程在调用write系统调用时有效地写入文件。对 的调用write是原子的:每次调用都会write写入一个不会被其他程序中断的字节序列。单个调用write将有效写入的数据量通常是有限制的:对于较大的数据,仅写入数据的开头,应用程序必须write再次调用。此外,许多程序执行缓冲: 他们在一个内存区域中积累数据,然后将这些数据写成一个块。某些程序在完成一行或其他有意义的分隔后刷新输出缓冲区。使用此类程序,您可以期望整行不会中断,只要它们不太长(最多几千字节;这取决于操作系统)。如果程序没有在有意义的位置刷新,而只是基于缓冲区大小,您可能会看到一个实例为 4kB,另一个实例为 4kB,然后第一个实例为 4kB,依此类推。


bah*_*mat 17

由于您使用的是>>,这意味着附加,因此每个实例的每一行输出都将按照其出现的顺序进行附加。

如果您的脚本输出在每个输出之间有 1 秒的延迟打印1\n出来5\n,并且实例 2 在 2.5 秒后启动,您将得到以下信息:

1
2
1
3
2
4
3
5
4
5
Run Code Online (Sandbox Code Playgroud)

所以回答你的问题:不。