如果我有一个 shell/python 脚本,它使用 sed 根据用户输入修改文件,然后两个用户同时或大约运行相同的脚本。同时,“sed”线程安全吗?或者也许这不是问题,因为第一个线程打开的 file_descripor 无论如何都会用于锁定文件?谢谢
答案1
我不会对可怕的术语吹毛求疵,但是,是的,GNU sed 及其-i
(“就地”)标志可以同时被多个进程安全地使用,而无需任何额外的锁定,因为sed
实际上并没有修改文件就地,但它将输出重定向到临时文件,如果一切顺利,它将把rename(2)
临时文件(移动)到原始文件,并且rename(2)
保证是原子的:
$ strace sed -i s/o/e/g foo.txt
open("foo.txt", O_RDONLY) = 3
...
open("./sedDe80VL", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
...
read(3, "foo\n", 4096) = 4
...
write(4, "fee\n", 4) = 4
read(3, "", 4096) = 0
...
close(3) = 0
close(4) = 0
rename("./sedDe80VL", "foo.txt") = 0
在任何时候,foo.txt
都将引用完整的原始文件或完整的处理文件,而绝不会引用两者之间的内容。
笔记:
这不能处理多个进程开始编辑文件而不等待其他进程完成编辑的情况,在这种情况下,只有完成最后“胜利”的进程(即擦除其他进程执行的更改) 。这不是数据完整性的问题,如果进程之间没有更高级别的协调,就无法处理(盲目锁定文件将导致死锁)。
目前,GNU sed 会将标准文件权限复制到新的 inode 中,但不会复制 ACL 和扩展属性。如果sed -i
在这样的文件上使用,所有额外的元数据都将丢失。恕我直言,这更多的是一个功能而不是错误或限制。
perl -i
以前的工作方式与sed -i
之前的版本非常不同5.28
;它首先制作文件的临时副本,截断到原始文件,然后将输出重定向到它。这是保留原始索引节点号和额外的元数据,但在perl -i
进程中断或多个perl -i
进程同时编辑文件的情况下,会完全丢弃文件的内容。请参阅讨论, 原本的犯罪(随后得到改进)和变更日志perl5280delta。
答案2
不建议在多个并行任务的同一个文件上使用 sed -i,但如果必须......
使其工作的模式是使用 信号。
要允许以功能线程感知的方式对同一文件上的 sed -i 进行异步调用,请使用咨询锁。
flock theSharedFile sed -i s/"userInput1"/"$userInput2"/g theSharedFile
Flock 在 SharedFile 上创建咨询锁,并且当锁空闲时(当没有其他集群在 SharedFile 上运行时),将使用其余参数执行 sed 命令。
如果两个不同的用户同时触发,第二个用户将等待前一个用户结束。就像这样,它将是一种功能齐全且线程安全的方法。任何“用户”更改都不会被丢弃并覆盖。
由于它是一个咨询锁,因此它只对集群有意义,并且不会导致任何类型的死锁。任何读取该文件的人都不会被锁定。请注意,如果文件很大,则等待锁的进程可能会花费大量时间。
您可以列出当前的锁lslocks
希望这对那里的人有帮助。谢谢你的时间。