如果我有一个 shell/python 脚本,它使用 sed 根据用户输入修改文件,然后两个用户同时或大约运行相同的脚本。同时,“sed”线程安全吗?或者这可能不是问题,因为第一个线程打开的 file_descripor 无论如何都将用于锁定文件?谢谢
我不会挑剔那些糟糕的术语,但是是的,带有-i
(“就地”)标志的GNU sed可以被多个进程同时安全地使用,而无需任何额外的锁定,因为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
Run Code Online (Sandbox Code Playgroud)
在任何时候,foo.txt
都将引用完整的原始文件或完整的处理过的文件,而不是介于两者之间的内容。
笔记:
这不能处理多个进程开始编辑文件而不等待其他进程完成编辑的情况,在这种情况下,只有最后完成的进程“获胜”(即擦除其他进程执行的更改) . 这不是数据完整性的问题,如果进程之间没有更高级别的协调,就无法处理(盲目锁定文件会导致死锁)。
目前,GNU sed 会将标准文件权限复制到新的 inode 中,但不会复制 ACL 和扩展属性。如果sed -i
在这样的文件上使用,所有额外的元数据都将丢失。恕我直言,这更像是一个功能,而不是一个错误或限制。
perl -i
以前的工作方式与sed -i
直到版本大不相同5.28
;它曾经首先制作文件的临时副本,截断到原始文件,然后将输出重定向到它。这会保留原始的 inode 编号和额外的元数据,但在perl -i
进程中断或多个perl -i
进程同时编辑文件的情况下会完全破坏文件的内容。请参阅讨论、原始提交(随后进行了改进)和perl5280delta 中的更改日志。