在 bash 中的文件中执行原子写入操作

在 bash 中的文件中执行原子写入操作

经历了狂欢之后文档,问题和我仍然不清楚如何在 bash 中对文件执行原子写入(追加)操作。我有一个在多个实例中运行的脚本,并且在某些时候必须将数据写入文件:

echo "$RESULT" >> `pwd`/$TEMP_DIR/$OUT_FILE

如何使所有并发运行的脚本对该文件的所有写入操作成为原子的(以便一个实例的数据不会与另一个实例的数据重叠)?

答案1

看来你需要使用flockman 的示例(http://linux.die.net/man/1/flock

(
flock -x 200

# Put here your commands that must do some writes atomically

) 200>/var/lock/mylockfile 

并将所有必须是原子的命令放入 () 中。

答案2

flock是联锁操作的方式之一。该实用程序是 util-linux 工具集的一部分,仅适用于 Linux。其他实用程序可在更广泛的平台上使用,它们基于 Daniel J. Bernstein 的setlockdaemontools 包中的实用程序:

  • setlock来自守护进程工具
  • setlock来自 Bruce Guenter 的 daemontools-encore
  • s6-setlock来自 Laurent Bercot 的 s6
  • chpst摘自 Gerrit Pape 的 runit
  • runlock来自韦恩·马歇尔的犯人
  • setlock来自我的 nosh 工具集

这些工具的运行模式与 M. Kurenkov 的答案中使用的模式略有不同(flock也可以使用,但在该答案中没有使用)。一个调用该setlock程序来链条负载至必须互锁的命令。 setlock它本身打开并锁定锁定文件,并为其进程中打开的文件描述符留下一个文件描述符。只要该进程存在,锁就会持续存在(除非链接的后续命令通过查找并关闭打开的文件描述符来显式释放锁)。

对于问题中的情况,必须互锁生成输出行的命令,并意识到这会调用外部的 echo代替 shell 内置echo命令:

setlock mylockfile echo "$RESULT" >> ./$TEMP_DIR/$OUT_FILE

在这种情况下,无需联锁以附加模式打开输出文件。如果是这样,则必须在锁内打开该文件,这需要使用诸如fdredir/redirfd:

setlock mylockfile fdredir --append 1 "./$TEMP_DIR/$OUT_FILE" echo "$RESULT"
如果需要的话,可以将其变成 shell 函数:

outfile() { setlock mylockfile fdredir --append 1 "./$TEMP_DIR/$OUT_FILE" "$@" ; } 
[...]
outfile 回显“$RESULT”
或者坚持使用 shell 语法并由在互锁下运行的第二个 shell 对其进行解释,如果一个 shell 变量未导出为环境变量,则需要一些重要的引用:

setlock mylockfile sh -c 'echo '"$RESULT"' >> "./'$TEMP_DIR'/'$OUT_FILE'"'

这当然可以推广到除了写入输出文件之外的其他事情:

setlock mylockfile sh -c '...互锁;东西 …'

相关内容