我们服务器上的某个人运行sed -i 's/$var >> $var2/$var > $var2/ *
更改插入以覆盖公共目录中的某些bash脚本.没什么大不了的,它首先经过测试grep
,它返回了预期的结果,只有他的文件会被触及.
他运行了脚本,现在文件夹中1400个文件的1200个文件有一个新的修改日期,但据我们所知,只有他的少量文件实际上已被更改.
$
sed正则表达式中的一些尾随空格或完全出乎意料的东西)?Joh*_*024 10
当GNU sed
成功编辑"就地"文件时,其时间戳会更新.为了理解原因,我们来看看如何编辑"就地":
创建一个临时文件来保存输出.
sed
处理输入文件,将输出发送到临时文件.
如果指定了备份文件扩展名,则输入文件将重命名为备份文件.
无论是否创建备份,临时输出都会移动(rename
)到输入文件.
GNU sed
不会跟踪是否对文件进行了任何更改.无论临时输出文件中的什么内容都通过移动到输入文件rename
.
这个过程有一个很好的好处:POSIX要求rename
是原子的.因此,输入文件永远不会处于错位状态:它既可以是原始文件,也可以是修改后的文件,而不会介于两者之间.
作为此过程的结果,任何sed
成功处理的文件都将更改其时间戳.
让我们考虑一下inputfile
:
$ cat inputfile
this is
a test.
Run Code Online (Sandbox Code Playgroud)
现在,在监督下strace
,让我们sed -i
以保证不会导致任何变化的方式运行它:
$ strace sed -i 's/XXX/YYY/' inputfile
Run Code Online (Sandbox Code Playgroud)
编辑后的结果如下:
execve("/bin/sed", ["sed", "-i", "s/XXX/YYY/", "inputfile"], [/* 55 vars */]) = 0
[...snip...]
open("inputfile", O_RDONLY) = 4
[...snip...]
open("./sediWWqLI", O_RDWR|O_CREAT|O_EXCL, 0600) = 6
[...snip...]
read(4, "this is\na test.\n", 4096) = 16
write(6, "this is\n", 8) = 8
write(6, "a test.\n", 8) = 8
read(4, "", 4096) = 0
[...snip...]
close(4) = 0
[...snip...]
close(6) = 0
[...snip...]
rename("./sediWWqLI", "inputfile") = 0
Run Code Online (Sandbox Code Playgroud)
如您所见,在文件句柄4上sed
打开输入文件.inputfile
然后./sediWWqLI
在文件句柄6上创建一个临时文件来保存输出.它从输入文件中读取并将其未更改地写入输出文件.完成此操作后,将调用rename
to overwrite inputfile
,更改其时间戳.
sed
源代码相关的源代码,是在execute.c
该文件sed
的目录源.从版本4.2.1:
ck_fclose (input->fp);
ck_fclose (output_file.fp);
if (strcmp(in_place_extension, "*") != 0)
{
char *backup_file_name = get_backup_file_name(target_name);
ck_rename (target_name, backup_file_name, input->out_file_name);
free (backup_file_name);
}
ck_rename (input->out_file_name, target_name, input->out_file_name);
free (input->out_file_name);
Run Code Online (Sandbox Code Playgroud)
ck_rename
是stdio函数的封面函数rename
.来源ck_rename
是sed/utils.c
.
如您所见,没有标记来确定文件是否实际更改. rename
被称为无论如何.
至于其时间戳没有改变的1400个文件中的200个,这意味着sed
这些文件以某种方式失败了.一种可能性是权限问题.
sed -i
和符号链接正如mklement0所述,应用sed -i
符号链接会产生令人惊讶的结果. sed -i
不更新符号链接指向的文件.而是使用新的常规文件sed -i
覆盖符号链接.
这是sed
对STDIO 的调用的结果rename
.如下所述man 2 rename
:
如果newpath引用符号链接,则链接将被覆盖.
mklement0报告说sed
Mac OSX 10.10上的(BSD)也是如此.
我使用以下解决方法,即单独查看每个文件,使用grep检查文件是否包含字符串,然后使用sed.不是很好,但有效......
for i in *;do grep mytext $i && sed -i -e 's/mytext/replacement/g' $i;done
Run Code Online (Sandbox Code Playgroud)