sed -i触摸不会更改的文件 [英] sed -i touching files that it doesn't change

查看:168
本文介绍了sed -i触摸不会更改的文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们服务器上的某人运行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.

  1. 为什么要sed'触摸'不变的文件.
  2. 为什么只触摸"一部分文件而不是全部文件.
  3. 它实际上是否改变了某些内容(可能是某些尾随空格或某些由于sed regex中的$而完全出乎意料的东西)?
  1. Why would sed 'touch' a file that it's not changing.
  2. Why would it only 'touch' a portion of the files and not all of them.
  3. 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:

  1. 已创建一个临时文件来保存输出.

  1. 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目录的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆