如何进行“更改后复制”操作?

Bro*_*ses 43 timestamps synchronization files

我想将一组文件从目录 A 复制到目录 B,但需要注意的是,如果目录 A 中的文件与目录 B 中的文件相同,则不应复制该文件(因此其修改时间不应为更新)。有没有办法用现有的工具做到这一点,而无需编写自己的脚本来做到这一点?

详细说明我的用例:我正在.c临时目录中自动生成一堆文件(通过必须无条件生成所有文件的方法),当我重新生成它们时,我只想复制已更改为实际源目录的那些,保留未更改的(使用它们的旧创建时间)保持不变,以便make知道不需要重新编译它们。(.c不过,并非所有生成的文件都是文件,因此我需要进行二进制比较而不是文本比较。)

(注意:这是我在/sf/ask/628708671/#8981762 上提出的问题,我在那里尝试为了加快我用来执行此操作的脚本文件的速度,但我突然想到,我真的应该问是否有比编写自己的脚本更好的方法来执行此操作——尤其是因为在 shell 中执行此操作的任何简单方法脚本将cmp在每对文件上调用类似的东西,并且启动所有这些进程需要很长时间。)

小智 34

rsync 可能是最好的工具。此命令有很多选项,因此请阅读手册页。我想你想要 --checksum 选项或 --ignore-times

  • @布鲁克斯摩西:没有。至少我的 `rsync` 版本没有。如果我这样做:`mkdir src dest; 回声 a>src/a; rsync -c src/* dest; 睡5;触摸 src/a; rsync -c src/* dest`,然后`stat dest/a` 显示它的 mtime 和 ctime 比 `src/a` 的 mtime 和 ctime 早 5 秒。 (4认同)
  • 这个答案的高评价是没有根据的。说“阅读手册页”几乎不比说“去谷歌搜索答案”更有帮助。 (3认同)
  • @BrooksMoses:我认为你可以依赖它:`rsync` 的工作流程是:1) 检查文件是否需要更新;2) 如果是,请更新文件。`--checksum` 选项表示它不应该被更新,所以 `rsync` 不应该继续第 2 步)。 (2认同)
  • @BrooksMoses:没有 `--checksum` 的 `--ignore-times` 将复制每个文件,因此也会更新时间戳,即使文件相同。 (2认同)

小智 32

您可以使用-u开关来cp喜欢这样:

$ cp -u [source] [destination]
Run Code Online (Sandbox Code Playgroud)

从手册页:

   -u, --update
       copy only when the SOURCE file is newer than the destination file or 
       when the destination file is missing
Run Code Online (Sandbox Code Playgroud)

  • 您好,欢迎来到该网站。我们希望这里的答案更实质性一些。例如,您可以解释“-u”标志的作用及其工作原理以及这将如何帮助 OP。但是,在这种特殊情况下,它对 OP 没有帮助,因为如果它们较新,它会复制相同的文件,因此更改它们的时间戳,这正是 OP 想要避免的。 (5认同)
  • 从对已删除的类似 A 的评论中:“这将不起作用,因为它也会复制相同的文件,如果源的时间戳较新(因此根据 OP 请求更新目标的时间戳)。” (2认同)
  • 根本没有回答这个问题,但我仍然觉得它很有用。 (2认同)

acu*_*ich 7

虽然使用rsync --checksum是“如果更改则复制”的一种很好的通用方法,但在您的特定情况下有一个更好的解决方案!

如果您想避免不必要地重新编译文件,您应该使用专为此目的而构建的ccache!事实上,它不仅可以避免对自动生成的文件进行不必要的重新编译,而且还可以在您这样做make clean并从头开始重新编译时加快速度。

接下来我肯定你会问,“它安全吗?” 嗯,是的,正如网站指出的那样:

安全吗?

是的。编译器缓存最重要的方面是始终生成与真实编译器将生成的输出完全相同的输出。这包括提供完全相同的目标文件和完全相同的编译器警告,如果您使用真正的编译器,则会产生这些警告。您应该能够告诉您正在使用 ccache 的唯一方法是速度。

而且它易于使用只需添加它作为前缀是CC=你的makefile行(或者你可以使用符号连接,但生成文件的方式可能会更好)。


Pat*_*aba 6

这应该可以满足你的需要

diff -qr ./x ./y | awk '{print $2}' | xargs -n1 -J% cp % ./y/
Run Code Online (Sandbox Code Playgroud)

在哪里:

  • x 是您更新的/新的文件夹
  • y 是您要复制到的目的地
  • awk 将从 diff 命令中获取每行的第二个参数(也许您需要一些额外的东西来处理带空格的文件名 - 现在无法尝试)
  • xargs -J% 会将文件名插入到 cp 的正确位置

  • -1,因为这过于复杂,不可移植(“-J”是 bsd 特定的;对于 GNU xargs,它是“-I”),并且如果两个位置不存在相同的文件集,则无法正常工作已经(如果我“touch x/boo”,那么 grep 会给我“Only in ./x: boo”,这会导致管道中出现错误)。使用专为该作业构建的工具,例如“rsync --checksum”。 (2认同)