gpt4 book ai didi

sed -i 触摸它不会改变的文件

转载 作者:行者123 更新时间:2023-12-04 13:13:27 24 4
gpt4 key购买 nike

我们服务器上有人跑了sed -i 's/$var >> $var2/$var > $var2/ *在公共(public)目录中的某些 bash 脚本中将插入更改为覆盖。没什么大不了的,它首先用 grep 进行了测试它返回了预期的结果,即只有他的文件会被触及。

他运行了脚本,现在文件夹中的 1400 个文件中的 1200 个文件有了新的修改日期,但据我们所知,实际上只有他的一小部分文件被更改了。

  • 为什么 sed 会“触摸”一个它没有改变的文件。
  • 为什么它只会“触摸”部分文件而不是全部文件。
  • 它是否真的改变了某些东西(可能是一些尾随空格或由于 sed 正则表达式中的 $ 而完全出乎意料的东西)?
  • 最佳答案

    当 GNU sed成功地“就地”编辑文件,其时间戳已更新。要了解原因,让我们回顾一下“就地”编辑是如何完成的:

  • 创建一个临时文件来保存输出。
  • sed处理输入文件,将输出发送到临时文件。
  • 如果指定了备份文件扩展名,则输入文件将重命名为备份文件。
  • 无论是否创建备份,临时输出都会移动 ( rename ) 到输入文件。

  • GNU sed不跟踪是否对文件进行了任何更改。临时输出文件中的任何内容都通过 rename 移动到输入文件中。 .

    这个过程有一个很好的好处: POSIX requires that rename be atomic .因此,输入文件永远不会处于损坏状态:它要么是原始文件,要么是修改后的文件,并且永远不会介于两者之间。

    作为这个过程的结果,任何文件 sed成功的进程将更改其时间戳。

    例子

    让我们考虑一下 inputfile :
    $ cat inputfile
    this is
    a test.

    现在,在 strace的监督下,让我们运行 sed -i以保证不会引起任何变化的方式对其进行处理:
    $ 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打开输入文件, inputfile , 在文件句柄 4 上。然后它创建一个临时文件 ./sediWWqLI在文件句柄 6 上,保存输出。它从输入文件中读取数据并将其原封不动地写入输出文件。完成后,调用 rename被覆盖 inputfile ,更改其时间戳。

    GNU sed源代码

    相关源码在 execute.c sed 的文件 the source的目录.从 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 .

    如您所见,没有保留任何标志来确定文件是否实际更改。 rename无论如何都被调用。

    时间戳未更新的文件

    至于 1400 个文件中的 200 个时间戳没有改变,这意味着 sed这些文件以某种方式失败。一种可能性是权限问题。
    sed -i和符号链接(symbolic link)

    mklement0 所述, 申请 sed -i符号链接(symbolic link)会导致令人惊讶的结果。 sed -i 不更新符号链接(symbolic link) 指向的文件.相反, sed -i 覆盖符号链接(symbolic link) 使用新的常规文件。

    这是调用 sed 的结果。使 STDIO rename .正如 man 2 rename 所记录的那样:

    if newpath refers to a symbolic link the link will be overwritten.



    mklement0 报告说 (BSD) sed 也是如此。在 Mac OSX 10.10 上。

    关于sed -i 触摸它不会改变的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27071019/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com