rsync 是同步文件的利器,一般用于多个机器之间的文件同步与备份,同时也支持在本地的不同目录之间互相同步文件。在这种场景下,rsync 远比 cp 命令更加合适,它只会同步需要更新的文件,默认情况下,rsync 通过比较文件的最后修改时间(mtime)和文件的大小(size)来确认哪些文件需要被同步过去。

最近刚好有一个需求,需要将文件从一个目录同步到另外一个目录去,我就首先试了下下面的命令:

# mkdir src dest
# echo hello > src/one.txt
# rsync --stats src/1.txt dest


这里加上 --stats 的目的是为了显示文件传输的详细信息。执行完成后文件已经同步到目标目录,非常简单,但是如果再执行一次,我们会非常尴尬地发现文件被再次同步过去:

# rsync --stats src/one.txt dest

Number of files: 1
Number of files transferred: 1
Total file size: 6 bytes
Total transferred file size: 6 bytes
Literal data: 6 bytes
Matched data: 0 bytes
File list size: 21
File list generation time: 0.001 seconds
File list transfer time: 0.000 seconds
Total bytes sent: 77
Total bytes received: 31

sent 77 bytes received 31 bytes 216.00 bytes/sec
total size is 6 speedup is 0.06


这里的问题让我抓狂很久,百思不得其解。但是如果我们运行时加上 -a 参数,文件就不会重复同步,下面是运行结果:

# rsync -a --stats src/one.txt dest

Number of files: 1
Number of files transferred: 0


翻了下帮助,找到 -a 选项的说明:

# rsync --help | grep -w -- -a
-a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)


使用这个选项后,会开启 archive mode,这时同步的时候会保留文件的属性,例如权限、用户及组、时间等等。然后,我们回忆下 rsync 如何是比较文件,大概可以猜出问题应该出在时间这一个属性上,准确地说是最后修改时间,也即所谓的 mtime。

那我们接下来,通过实际例子来确认下我们的猜想:

# rm src/one.txt 
# rsync src/one.txt dest
# stat -c %y src/one.txt dest/one.txt
2013-10-15 11:28:15.000000000 +0800
2013-10-15 11:28:17.000000000 +0800


果然,不带选项同步时源和目标文件的 mtime 是不一样的,这就导致下次 rsync 的时候,仍然误以为文件需要同步。接下来,我们改变下 dest/one.txt 的 mtime,然后再执行一次:

# touch -r src/one.txt dest/one.txt
# rsync --stats src/one.txt dest

Number of files: 1
Number of files transferred: 0


这下 rsync 不会再同步 one.txt 了。当然,还有其它的选项也能够有同样的效果,比如 --update 或者 --size-only,都可以尝试下。

当然大多数情况下,还是建议以下几个选项一起使用:

# rsync -avzS --partial src dest