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

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

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

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

(注:这源于我提出的问题https://stackoverflow.com/questions/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981762#8981762,我试图加快我用来执行此操作的脚本文件的速度,但我突然想到,我真的应该问是否有比编写自己的脚本更好的方法来执行此操作 - 特别是因为任何简单的方法在 shell 脚本中执行此操作将cmp在每对文件上调用类似的操作,并且启动所有这些进程需要很长时间。)

답변1

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

$ cp -u [source] [destination]

从手册页:

   -u, --update
       copy only when the SOURCE file is newer than the destination file or 
       when the destination file is missing

답변2

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

답변3

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

如果您想避免不必要的重新编译文件,您应该使用缓存正是为了这个目的而建造的!事实上,它不仅可以避免对自动生成的文件进行不必要的重新编译,而且还可以加快您从头开始make clean重新编译的速度。

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

安全吗?

是的。编译器缓存最重要的方面是始终产生与真实编译器产生的输出完全相同的输出。这包括提供完全相同的目标文件以及使用真实编译器时会产生的完全相同的编译器警告。您应该能够判断您正在使用 ccache 的唯一方法是速度。

这是便于使用只需将其作为前缀添加到CC=makefile 行中即可(或者您可以使用符号链接,但 makefile 方式可能更好)。

답변4

我喜欢用一致赞成,rsync因为它支持多个master,已经分别设置了我的 ssh 密钥和 VPN。

因此,在只有一台主机的 crontab 中,我让它们每 15 分钟同步一次:

*/15 * * * * [ -z "$(pidof unison)" ] && (超时25m unison -sortbysize -ui text -batch -times /home/master ssh://192.168.1.12//home/master -path dev -logfile /tmp/sync.master.dev.log) &> /tmp/sync.master.dev.log

然后我可以在任何一边发展,变化就会传播。事实上,对于重要的项目,我最多有 4 台服务器镜像同一棵树(其中 3 台服务器从 cron 一致运行,指向不运行的服务器)。事实上,Linux 和 Cygwin 主机是混合的——除了不要指望在 cygwin 环境之外的 win32 中感知软链接。

如果您走这条路,请在空的一侧制作初始镜子-batch,不要,即

unison -ui text  -times /home/master ssh://192.168.1.12//home/master -path dev

当然有一个配置可以忽略备份文件、档案等:

 ~/.unison/default.prf :
# Unison preferences file
ignore = Name {,.}*{.sh~}
ignore = Name {,.}*{.rb~}
ignore = Name {,.}*{.bak}
ignore = Name {,.}*{.tmp}
ignore = Name {,.}*{.txt~}
ignore = Name {,.}*{.pl~}
ignore = Name {.unison.}*
ignore = Name {,.}*{.zip}

    # Use this command for displaying diffs
    diff = diff -y -W 79 --suppress-common-lines

    ignore = Name *~
    ignore = Name .*~
    ignore = Path */pilot/backup/Archive_*
    ignore = Name *.o

관련 정보