如果我有一个命令
$ ./script >> file.log
被调用两次,第二次调用发生在第一个调用结束之前,会发生什么?
第一次调用是否获得输出文件的独占锁?如果是这样,第二个脚本在尝试写入时是否会失败,或者 shell 是否接受输出(允许脚本结束)并抛出错误?
或者日志文件是否被写入两次?
答案1
Unix 系统总体上避免强制锁。在某些情况下,内核会锁定文件以防止用户程序修改,但如果文件只是由另一个程序写入,则不会。没有 UNIX 系统会因为程序正在写入文件而锁定文件。
如果您希望脚本的并发实例不互相打扰,则需要使用显式锁定机制,例如flock
lockfile
。
当您打开文件进行追加时(确实>>
如此),每个程序都保证始终写入文件的末尾。因此,多个实例的输出永远不会互相覆盖,如果它们轮流写入,它们的输出将与写入的顺序相同。
可能发生的坏事是,如果其中一个实例写入了多个输出块并期望它们一起输出。在一个实例的连续写入之间,其他实例可以执行自己的写入。例如,如果实例 1 写入foo
,然后实例 2 写入hello
,然后只有实例 2 写入bar
,则该文件将包含foohellobar
.
当进程调用系统调用时,它会有效地写入文件write
。对 的调用write
是原子的:每次调用都会write
写入不会被其他程序中断的字节序列。单次调用有效写入的数据量通常存在限制write
:对于较大的大小,仅写入数据的开头,应用程序必须write
再次调用。此外,许多程序执行缓冲:它们在内存区域中累积数据,然后将这些数据写入一个块中。某些程序在完成行或其他有意义的分隔后刷新输出缓冲区。使用此类程序,您可以预期整行不会被中断,只要它们不太长(最多几千字节;这取决于操作系统)。如果程序不在有意义的位置刷新,而仅根据缓冲区大小进行刷新,您可能会看到一个实例中的 4kB,然后是另一个实例中的 4kB,然后又是第一个实例中的 4kB,依此类推。
答案2
由于您使用的是>>
,这意味着附加,因此每个实例的每一行输出都将按照其发生的顺序附加。
如果您的脚本输出打印1\n
完毕5\n
,每个输出之间有 1 秒的延迟,并且实例 2 在 2.5 秒后启动,您将得到以下结果:
1
2
1
3
2
4
3
5
4
5
所以回答你的问题:不。