sed -i触摸不会更改的文件 [英] sed -i touching files that it doesn't change
问题描述
我们服务器上的某人运行sed -i 's/$var >> $var2/$var > $var2/ *
来将插入更改为覆盖公共目录中某些bash脚本中的覆盖.没什么大不了的,它首先使用grep
进行了测试,并且返回了仅会触摸他的文件的预期结果.
Someone on our server ran sed -i 's/$var >> $var2/$var > $var2/ *
to change inserts to overwrites in some bash scripts in a common directory. No big deal, it was tested first with grep
and it returned the expected results that only his files would be touched.
他运行了脚本,现在文件夹中的1400个文件中的1200个文件具有新的修改日期,但据我们所知,实际上只有一小部分文件被更改.
He ran the script and now 1200 files of the 1400 in the folder have a new modified date, yet as far as we can tell, only his small handful of files were actually changed.
- 为什么要sed'触摸'不变的文件.
- 为什么只触摸"一部分文件而不是全部文件.
- 它实际上是否改变了某些内容(可能是某些尾随空格或某些由于sed regex中的
$
而完全出乎意料的东西)?
- Why would sed 'touch' a file that it's not changing.
- Why would it only 'touch' a portion of the files and not all of them.
- Did it actually change something (maybe some trailing white space or something totally unexpected because of the
$
's in the sed regex)?
推荐答案
当GNU sed
成功就地"编辑文件时,其时间戳将更新.要了解原因,让我们回顾一下如何进行就地"
When GNU sed
successfully edits a file "in-place," its timestamp is updated. To understand why, let's review how edit "in-place" is done:
-
已创建一个临时文件来保存输出.
A temporary file is created to hold the output.
sed
处理输入文件,将输出发送到临时文件.
sed
processes the input file, sending output to the temporary file.
如果指定了备份文件扩展名,则将输入文件重命名为备份文件.
If a backup file extension was specified, the input file is renamed to the backup file.
Whether a backup is created or not, the temporary output is moved (rename
) to the input file.
GNU sed
不跟踪是否对该文件进行了任何更改.临时输出文件中的所有内容都会通过rename
移到输入文件中.
GNU sed
does not track whether any changes were made to the file. Whatever is in the temporary output file is moved to the input file via rename
.
此过程有一个很好的好处: POSIX要求rename
是原子的.因此,输入文件永远不会处于混乱状态:它是原始文件还是修改后的文件,并且永远不会处于中间状态.
There is a nice benefit to this procedure: POSIX requires that rename
be atomic. Consequently, the input file is never in a mangled state: it is either the original file or the modified file and never part way in-between.
此过程的结果是,sed
成功处理的任何文件都会更改其时间戳.
As a result of this procedure, any file that sed
successfully processes will have its timestamp changed.
让我们考虑一下inputfile
:
$ cat inputfile
this is
a test.
现在,在strace
的监督下,让我们以保证不会造成任何更改的方式在其上运行sed -i
:
Now, under the supervision of strace
, let's run sed -i
on it in a way guaranteed to cause no changes:
$ strace sed -i 's/XXX/YYY/' inputfile
编辑后的结果如下:
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
如您所见,sed
在文件句柄4上打开输入文件inputfile
.然后在文件句柄6上创建一个临时文件./sediWWqLI
,以保存输出.它从输入文件读取并将其原样写入输出文件.完成此操作后,将调用rename
覆盖inputfile
,更改其时间戳.
As you can see, sed
opens the input file, inputfile
, on file handle 4. It then creates a temporary file, ./sediWWqLI
on file handle 6, to hold the output. It reads from the input file and writes it unchanged to the output file. When this is done, a call to rename
is made to overwrite inputfile
, changing its timestamp.
相关的源代码位于sed
目录中的execute.c
文件中. 2.1-10.debian.tar.gz"rel =" nofollow noreferrer>源.从4.2.1版开始:
The relevant source code is in the execute.c
file of the sed
directory of the source. From version 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);
ck_rename
是stdio函数rename
的覆盖函数. ck_rename
的来源在sed/utils.c
中.
ck_rename
is a cover function for the stdio function rename
. The source for ck_rename
is in sed/utils.c
.
如您所见,不保留任何标志来确定文件是否实际更改. rename
都会被调用.
As you can see, no flag is kept to determine whether the file actually changed or not. rename
is called regardless.
对于时间戳不变的1400个文件中的200个,这意味着sed
在这些文件上以某种方式失败.一种可能性是权限问题.
As for the 200 of the 1400 files whose timestamps did not change, that would mean that sed
somehow failed on those files. One possibility would be a permissions issue.
如 mklement0 所述,将sed -i
应用于符号链接会导致令人惊讶的结果. sed -i
不更新符号链接指向的文件.相反,sed -i
用新的常规文件覆盖符号链接.
As noted by mklement0, applying sed -i
to a symbolic link leads to a surprising result. sed -i
does not update the file pointed to by the symbolic link. Instead, sed -i
overwrites the symbolic link with a new regular file.
这是sed
对STDIO rename
进行调用的结果.如man 2 rename
所述:
This is a result of the call that sed
makes to the STDIO rename
. As documented by man 2 rename
:
如果newpath引用符号链接,则该链接将被覆盖.
if newpath refers to a symbolic link the link will be overwritten.
mklement0报告说,Mac OSX 10.10上的(BSD)sed
也是这样.
mklement0 reports that this is also true of the (BSD) sed
on Mac OSX 10.10.
这篇关于sed -i触摸不会更改的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!