sed
创建一个临时文件,将输出写入该文件,然后在原始文件的顶部重命名该临时文件。
您可以使用观看发生的情况strace
:
$ strace -e trace=file sed -i -e '' a
execve("/usr/bin/sed", ["sed", "-i", "-e", "", "a"], [/* 34 vars */]) = 0
<...trimmed...>
open("a", O_RDONLY) = 3
open("./sedxvhRY8", O_RDWR|O_CREAT|O_EXCL, 0600) = 4
rename("./sedxvhRY8", "a") = 0
+++ exited with 0 +++
这会记录所有文件操作sed
:创建一个新文件(安全地使用O_CREAT|O_EXCL
),将数据写入其中,然后将其移回到我的原始文件上方a
。
sed -i
接受用于备份的后缀,在这种情况下,它将后缀先移开(而不是在顶部重命名)。在大多数BSD中,该参数是必需sed
的。在这种情况下,有时会在目录中根本没有名称正确的文件。
perl
在最新版本中,将打开输入文件,然后将其删除并创建一个具有相同名称的新文件:
open("a", O_RDONLY) = 3
unlink("a") = 0
open("a", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4
当您删除(unlink
)已打开的文件时,只要保持打开状态,就可以保留对该文件的访问权限,这样它就可以继续从删除的文件中读取数据。这样,可以perl
直接写入输出文件,而不是临时文件:不会创建其他文件,但是,如果您在此过程中读取文件,则将获得部分内容,这与sed
的方法不同。还有很短的时间,没有名称正确的文件,它是在流程的开始而不是结尾(如所示sed -i .bak
)。
双方sed
并perl
会:
- 用普通文件替换符号链接。
- 断开硬链接。
- 如果可能,保留组的所有权。
- 如果文件
setgid
属于您不在的组,并且不是root用户,则使用默认组(如果该目录包含位,则使用父目录的组)创建文件。
- 如果您是root用户,则保留文件所有权。
- 保留基本权限。
- 如果结果组与其开始的组相同,则保留
setuid
和setgrp
位。
- 保留粘性位。
- 不保留xattrs。
sed
将:
- 保留ACL (在Linux上;我不了解其他 ACL )。
perl
将:
在具有GNU的Linux sed
和带有(从FreeBSD派生的)Mac OS X的Linux上,以上情况是正确的sed
。