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