是“sed”线程安全的

ter*_*eys 4 linux sed python

如果我有一个 shell/python 脚本,它使用 sed 根据用户输入修改文件,然后两个用户同时或大约运行相同的脚本。同时,“sed”线程安全吗?或者这可能不是问题,因为第一个线程打开的 file_descripor 无论如何都将用于锁定文件?谢谢

mos*_*svy 9

我不会挑剔那些糟糕的术语,但是是的,带有-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 中的更改日志。

  • 它不会完全是垃圾,但丢失更改仍然是一个问题。该问题指的是文件“被锁定”,而锁定通常是指等待第一个完成的第二个`sed`进程。对他们来说,这可能只是一个糟糕的术语;很难说他们真正关心什么,但那个特定的问题仍然是可能的。 (8认同)
  • 但可能发生的情况是,`sed` 的两个副本开始读取文件,进行不同的更改,将它们存储到各自的临时文件中,然后将它们一个接一个地重命名到位,而不考虑存在另一个`sed 的事实` 同时处理文件。`sed` 进程之一所做的更改将丢失。 (3认同)
  • @ilkkachu 仍然是完全一致的——该文件将被两个进程依次修改(以任何顺序)或仅由其中一个进程修改。该文件绝不会包含因两个进程同时修改它而产生的垃圾。 (2认同)