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


34

我想将一组文件从目录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
您可以用来diff -qr dirA dirB分别查看dirA和和唯一的文件dirB

1
@ brooks-moses这确实是适合ccache的工作!
aculich 2012年

3
@hesse如果要显示唯一文件,则可以使用diff,但是如果您想查看已更改的内容,请使用rsync -avnc或漫长的路rsync --archive --verbose --dry-run --checksum
aculich 2012年

Answers:


29

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


我应该注意到,我已经尝试过了,但没有成功。这两个选项仅影响rsync 是否执行复制-但是,即使它不执行复制,它也会将目标文件的修改时间更新为与源文件相同的修改时间(如果-t指定了该选项)或同步时间。 (如果-t未指定)。
Brooks Moses

4
@布鲁克斯·摩西:不是。至少我的版本rsync没有。如果我这样做:mkdir src dest; echo a>src/a; rsync -c src/* dest; sleep 5; touch src/a; rsync -c src/* dest,则stat dest/a表明其mtime和ctime比的早5秒src/a
2012年

@angus:呵呵。好的,你是对的。关键似乎是该--checksum选项,尽管linux.die.net/man/1/rsync绝对包含任何内容,这暗示它对是否修改了修改日期有任何影响,但是它仍然导致保留了目标修改日期。不动摇。(另一方面,该--ignore-times选项没有效果;使用该选项,修改日期仍会更新。)但是,鉴于此似乎完全没有记载,我可以依靠它吗?
Brooks Moses

2
@BrooksMoses:我认为您可以依靠它:rsync的工作流程是:1)检查文件是否需要更新;2)如果是,请更新文件。该--checksum选项说,它不应该被更新,所以rsync不应该继续执行步骤2)。
enzotib 2012年

2
@BrooksMoses:--ignore-times没有--checksum将复制所有文件,所以也更新时间戳,即使文件是相同的。
enzotib 2012年

13

您可以使用-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

4
嗨,欢迎来到该网站。我们希望这里的答案会更多一些。例如,您可能已经包含了有关-u标志作用以及它如何工作以及这将如何帮助OP的解释。但是,在这种特殊情况下,这不会给OP带来帮助,因为OP将复制相同的文件(如果文件较新),因此会更改其时间戳,这正是OP希望避免的事情。
terdon

1
在对已经删除的类似A的评论中:“如果源时间戳较新(因此,根据OP请求更新目标时间戳),它将复制相同的文件,因此,这将不起作用。”
slm

根本不回答问题,但我仍然发现它很有用。
user31389 '16

7

尽管使用rsync --checksum“复制更改后复制”是一种很好的通用方法,但是在您的特定情况下,还有一个更好的解决方案!

如果要避免不必要地重新编译文件,则应使用为此目的而专门构建的ccache!实际上,它不仅可以避免不必要地重新编译自动生成的文件,还可以加快处理速度,make clean并从头开始重新编译。

接下来,我确定您会问:“安全吗?” 是的,正如网站所指出的:

安全吗?

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

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


1
最初我误会了,以为您建议我使用ccache进行部分生成,但是现在我明白了–您的建议是我只复制所有文件,然后在构建过程中使用ccache,从而避免了重建那些没变 这是个好主意,但就我而言,它做得不好-我有数百个文件,通常一次只能更改一两个文件,并且在Cygwin下运行,只需启动数百个ccache进程即可查看每个文件文件将需要几分钟。尽管如此,还是投票赞成,因为这对大多数人来说都是一个很好的答案!
Brooks Moses

不,我不是建议您复制所有文件,而是可以就地自动生成.c文件(删除复制步骤并直接写入文件)。然后只需使用ccache。我不知道启动数百个ccache进程是什么意思……这只是gcc的轻量级包装,它相当快,并且也将加快重建项目其他部分的速度。您是否尝试过使用它?我希望看到使用复制方法与ccache的时间比较。实际上,您可以结合使用这两种方法来获得两者的好处。
aculich

1
是的,好的,我现在了解有关复制的信息。为了澄清,我的意思是:如果我就地生成文件,那么我必须调用ccache file.c -o file.o几百次或等效的调用,因为有几百个file.c文件。当我用它cmp而不是ccache花几分钟的时候才做了-而且cmp它轻巧ccache。问题在于,在Cygwin上,即使对于一个完全琐碎的过程,启动过程花费的时间也可以忽略不计。
Brooks Moses

1
作为一个数据点,for f in src/*; do /bin/true.exe; done需要30秒,是的。无论如何,我更喜欢基于Windows的编辑器,除了这种时序问题之外,Cygwin在我的工作流程中也可以很好地工作,因为它是轻量级的地方,可以在不上传到构建服务器的情况下在本地进行测试。将我的外壳程序和编辑器放在同一操作系统中很有用。:)
Brooks Moses'2

1
如果您想使用基于Windows的编辑器,则可以在安装Guest Additions的情况下使用“ 共享文件夹”轻松完成此操作...但是,嘿,如果Cygwin适合您,那么我该怎么说呢?不得不跳过像这样的怪圈似乎很可耻...而且通常在VM中编译也更快。
aculich

3

这应该做你需要的

diff -qr ./x ./y | awk '{print $2}' | xargs -n1 -J% cp % ./y/

哪里:

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

1
-1,因为它过于复杂,不可移植(-J是bsd特定的;对于GNU xargs是-I),并且如果两个位置都没有相同的文件集(如果我touch x/boo然后grep给我),它将无法正常工作Only in ./x: boo这会导致管道中的错误)。使用为工作而构建的工具,例如rsync --checksum
aculich 2012年

或更妙的是,对于这种特定情况,请使用ccache
aculich 2012年

+1是因为它具有一组众所周知的命令,我可以中断使用这些命令来执行类似的任务(此处是做比较),对于此特定任务,rsync仍然会更好
ntg

3

我喜欢使用统一rsync因为它支持多个主机,并且已经分别设置了我的ssh密钥和vpn。

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

* / 15 * * * * [-z“ $(pidof unison)”] &&(超时25m一致-sortbysize -ui文本-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

我看了看,但是找不到一个unison选项,表示“不要更新文件的最后修改日期”。有一个吗?否则,这是一个完全不同的问题的好答案。
Brooks Moses

1
-times为我做到了。我认为,Unison也具有空转模式。
马科斯(Marcos)

好吧,设置times=false(或取消设置-times)可以做到这一点。我不知道我以前在文档中是怎么错过的。谢谢!
Brooks Moses

乐意效劳。在保留诸如modtimes,权限和软链接之类的东西时,我是一个顽固的人。经常被忽略
Marcos

1

虽然rsync --checksum是正确的答案,但请注意,此选项与不兼容--times,并且--archive包括在内--times,因此,如果需要rsync -a --checksum,您确实需要rsync -a --no-times --checksum


您说“不兼容”是什么意思?
ov

“正确答案”是什么意思?
thoni56
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.