参考资料:骏马金龙的rsync系列。该博主的博文质量很好,推荐大家关注。

环境

操作系统:CentOS Linux release 7.5.1804 (Core)

软件:rsync  version 3.1.2  protocol version 31

前言

rsync可以实现scp的部分远程复制功能(支持本地到远程复制和远程到本地复制,但是不支持远程到远程复制;scp可以支持远程到远程复制)、cp的本地复制功能、rm的删除功能和“ls -l”的显示详细信息文件列表功能。

注意,rsync的初衷是实现两端主机之间的数据同步,上述功能只是作为辅助,并且其实现方式是与scp/cp/rm/ls这些命令不同的。

rsync有自己的一套算法以及算法实现机制,日常使用的话可以无需了解。但是,如果想要看懂rsync的man手册或者官方文档,想要通过-vvvv选项看懂rsync的执行过程,那么还是有必要了解rsync的原理的。

同步基础

同步涉及到了源文件(源主机、发送端)和目标文件(目标主机、接收端)、本地主机和远程主机、以及以哪边的主机上的文件为基准的概念。以谁为基准,就是以谁作为源文件。

  • 想让本地主机上的文件和远程主机上的文件保持同步。则以远程主机上的文件为基准(即作为源文件),将其拉取到本地主机覆盖本地主机的文件(即作为目标文件)。
  • 想让远程主机上的文件和本地主机上的文件保持同步。则以本地主机上的文件为基准(即作为源文件),将其推送到远程主机覆盖远程主机的文件(即作为目标文件)。
  • 本地主机和远程主机,既可以作为源主机/发送端,也可以作为目标主机/接收端,看具体的情况而定。

同步的过程,还涉及到其他的问题。

  • 是否删除源主机上没有但是目标主机上多出来的文件?
  • 目标文件的mtime比源文件的mtime更(gèng)新的时候,是否覆盖?
  • 遇到字符链接时,是同步字符链接本身还是其所指向的文件?即是否追踪字符链接文件?
  • 目标文件已存在时,是否做备份?
  • 等等其他情况。

上面这些操作,都是需要rsync来完成的,这也就是为什么在使用rsync的时候要求源和目标主机都需要安装有rsync程序包。

rsync的同步由检查模式和同步模式两部分构成。

检查模式

检查模式用于检查哪些文件应该被同步,哪些文件不应该被同步。比如--exclude选项排除了不应该被同步的文件。默认情况下,rsync使用quick check算法来检查源文件和目标文件的size(文件大小)与mtime。当size或者mtime不同的时候,就会判定文件应该被同步。

可以通过一些选项来修改检查模式,例如--size-only用于指明将仅检查文件的size而不检查mtime。

还有其他的选项也可以用于修改检查模式,弹性十足。

同步模式

同步模式用于处理上面所说的“是否删除本地主机上没有但是远程主机上多出来的文件?”之类的问题。同步模式也有许多选项可以指定,也是弹性十足。

一般情况下我们是修改同步模式,少数情况下才会修改检查模式,因为后者的修改容易引起性能的较大改动(例如--checksum)或者没有正确同步应该同步的文件(例如--size-only)。

三种工作方式

rsync有三种工作方式,即三种语法格式,如下。

Local:  rsync [OPTION...] SRC... [DEST]

Access via remote shell:
Pull: rsync [OPTION...] [USER@]HOST:SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST:DEST Access via rsync daemon:
Pull: rsync [OPTION...] [USER@]HOST::SRC... [DEST]
rsync [OPTION...] rsync://[USER@]HOST[:PORT]/SRC... [DEST]
Push: rsync [OPTION...] SRC... [USER@]HOST::DEST
rsync [OPTION...] SRC... rsync://[USER@]HOST[:PORT]/DEST
  1. 第一种方式是上述的Local部分,为本地主机内部的同步。
  2. 第二种方式是上述的remote shell部分,为不同主机通过远程shell实现同步。
  3. 第三种方式是上述的rsync daemon部分,为不同主机通过网络套接字实现同步。这种方式在指定daemon的时候有两种形式。有双冒号形式和URL形式,都是可以的,个人倾向于URL形式,比较不会和单冒号形式相似。前面演示的示例都是本地主机或者远程shell,最后再单独讲rsync daemon方式。

前两者的本质是基于管道;第三种是需要先在远程主机上运行一个daemon,监听在某个端口上,然后本地主机通过网络套接字与其通信。

还有一种特殊的方式,是基于远程shell连接上之后,在远程主机上临时运行一个daemon,当数据同步完毕后,daemon也会结束。这种方式的命令行语法类似rsync daemon模式,不同的点在于选项需要指明-e或者--rsh。

本文中我们将其称为“临时daemon”,注意,这只是个人对其称呼,非官方。

命令的参数可以有多个;当指定多个的时候,只有最后一个表示目标文件,其余都为源文件,目标文件若不存在则自动创建为目录,若存在则必须得是目录,否则报错。

[root@C7 ~]# file /tmp/.txt
/tmp/.txt: empty
[root@C7 ~]# rsync /etc/fstab /etc/inittab /tmp/.txt
ERROR: destination must be a directory when copying more than file
rsync error: errors selecting input/output files, dirs (code ) at main.c() [Receiver=3.1.]

如果参数只有一个SRC的话,那么等同于“ls -l”。

[root@c7-client ~]# rsync /etc/fstab
-rw-r--r-- // :: fstab
[root@c7-client ~]# rsync /etc/ssh/
drwxr-xr-x // :: .
-rw-r--r-- , // :: moduli
-rw-r--r-- , // :: ssh_config
-rw-r----- // :: ssh_host_ecdsa_key
-rw-r--r-- // :: ssh_host_ecdsa_key.pub
-rw-r----- // :: ssh_host_ed25519_key
-rw-r--r-- // :: ssh_host_ed25519_key.pub
-rw-r----- , // :: ssh_host_rsa_key
-rw-r--r-- // :: ssh_host_rsa_key.pub
-rw------- , // :: sshd_config
[root@c7-client ~]# rsync root@192.168.17.7:/etc/fstab
root@192.168.17.7's password:
-rw-r--r-- // :: fstab
[root@c7-client ~]# rsync root@192.168.17.7:/etc/ssh/
root@192.168.17.7'
s password:
drwxr-xr-x // :: .
-rw-r--r-- , // :: moduli
-rw-r--r-- , // :: ssh_config
-rw-r----- // :: ssh_host_ecdsa_key
-rw-r--r-- // :: ssh_host_ecdsa_key.pub
-rw-r----- // :: ssh_host_ed25519_key
-rw-r--r-- // :: ssh_host_ed25519_key.pub
-rw-r----- , // :: ssh_host_rsa_key
-rw-r--r-- // :: ssh_host_rsa_key.pub
-rw------- , // :: sshd_config

当使用远程shell的时候,会提示我们输入远程主机的用户密码。由于远程shell方式是基于SSH,因此可以事先配置好SSH的免密登录,这样就无需密码了。

[root@c7-client ~]# rsync root@192.168.17.7:/etc/fstab
-rw-r--r-- // :: fstab

本地主机文件和目录的复制,类似cp命令。

[root@c7-client ~]# rsync /etc/fstab /tmp/
[root@c7-client ~]# ls -l /etc/fstab /tmp/fstab
-rw-r--r--. root root Dec : /etc/fstab
-rw-r--r--. root root Dec : /tmp/fstab
[root@c7-client ~]# rsync -r /etc/ssh /tmp/
[root@c7-client ~]# ls /{etc,tmp}/ssh/
/etc/ssh/:
moduli ssh_config sshd_config ssh_host_ecdsa_key ssh_host_ecdsa_key.pub ssh_host_ed25519_key ssh_host_ed25519_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub /tmp/ssh/:
moduli ssh_config sshd_config ssh_host_ecdsa_key ssh_host_ecdsa_key.pub ssh_host_ed25519_key ssh_host_ed25519_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub

复制或者同步目录的时候,需要注意一点,如果源目录的末尾没有斜线,则表示将源目录整个复制到目标目录下,就如同上面的例子;

如果源目录的末尾有斜线,则表示将源目录下的内容复制到目标目录下,如下所示。

[root@c7-client ~]# rsync -r /etc/ssh/ testdir/
[root@c7-client ~]# ls /etc/ssh/ testdir/
/etc/ssh/:
moduli ssh_config sshd_config ssh_host_ecdsa_key ssh_host_ecdsa_key.pub ssh_host_ed25519_key ssh_host_ed25519_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub testdir/:
moduli ssh_config sshd_config ssh_host_ecdsa_key ssh_host_ecdsa_key.pub ssh_host_ed25519_key ssh_host_ed25519_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub

远程shell之间的文件同步。

[root@c7-client ~]# rsync c7-client.txt root@192.168.17.7:/root/
[root@c7-client ~]# rsync root@192.168.17.7:/root/c7.txt .

远程shell之间的目录同步。

[root@c7-client ~]# touch testdir/rsync{,,}.txt
[root@c7-client ~]# rsync -r testdir/ root@192.168.17.7:/root/
[root@C7 ~]# ls -l /root/rsync{,,}.txt
-rw-r--r-- root root Dec : /root/rsync1.txt
-rw-r--r-- root root Dec : /root/rsync2.txt
-rw-r--r-- root root Dec : /root/rsync3.txt
[root@c7-client ~]# rsync -r root@192.168.17.7:/root/rrr .
[root@c7-client ~]# ls -l rrr/
total
-rw-r--r--. root root Dec : l.txt
-rw-r--r--. root root Dec : w.txt
-rw-r--r--. root root Dec : z.txt

选项与示例

-v, --verbose:用于显示同步中的详细信息,-vvvv可以显示更详细的信息,一般是用于排错的时候使用。v的个数越多,显示的信息越详细。

--partial:默认情况下,当传输中断的时候,rsync会将已传输一半的目标文件删除;如果使用该选项,则不会删除,这样子可以提高再次传输的速度,感觉类似于断点重传。

--progress:在同步的时候显示进度,类似如下。

  %  .64kB/s    ::

-P:该选项是--partial和--progress的结合,当同步的时间较长(文件较大较多或者网络不佳)的时候,可以使用该选项。

-n, --dry-run:用于测试,不会真正执行同步操作,而是模拟真实操作,并且模拟真实的输出,常配合-v或者-vvvv来查看rsync是否执行正常。

-a, --archive:归档模式,等同于-rlptgoD,它保留了源文件的大部分元数据。但是它不包含-H选项,因为查找多链接的文件太消耗资源。

-r, --recursive:递归,用于同步目录。如果不加该选项,当源文件是一个目录的时候,会跳过,并返回被跳过的目录名称。

[root@C7 tmp]# rsync -v /foo/ /tmp/
skipping directory . sent bytes received bytes 56.00 bytes/sec
total size is speedup is 0.00
[root@C7 tmp]# rsync -v /foo /tmp/
skipping directory foo sent bytes received bytes 56.00 bytes/sec
total size is speedup is 0.00

这里从输出信息中也可以看出源文件如果是目录,那么末尾是否带斜线的差异。

[root@C7 tmp]# rsync -rv /foo/ /tmp/
sending incremental file list
bar/baz.c sent bytes received bytes 334.00 bytes/sec
total size is speedup is 0.00

-t, --times:保留文件的mtime,由于rsync默认检查模式使用quick check算法,因此建议每次同步都应该使用-t或者-a选项,否则发送端每次都会将很可能是相同的文件加入文件列表,导致了系统资源的浪费。

-o, --owner:保留文件的属主。

-g, --group:保留文件的属组。

--chown=USER:GROUP:文件同步后修改目标文件的ownership。该选项其实等同于“--usermap=*:USER --groupmap=*:GROUP”。不过该选项的实现是内部调用了--usermap和--groupmap,因此该选项不可以与这两个选项混合使用。如果想要让--chown正常使用,不可缺少-o和-g选项。

-p, --perms:保留文件的读写执行权限,不包含其他特殊权限。

--chmod:文件同步后修改目标文件的权限。可根据文件是普通文件或者目录分别设置不同的权限。如果是普通文件则会加上前缀F,目录则会加上前缀D。用法类似如下。

--chmod=Dg+s,ug+w,Fo-w,+X
--chmod=D2775,F664

如果想要让--chown正常使用,不可缺少-o和-g选项。

因此,如果想要让--chown和--chmod都正常使用的话,使用-a选项即可!但是具体的原因目前未知,应该是rsync对待所有权(ownership)和权限(permission)的理解与我们人脑不同。

让我们来验证一下-togp选项的作用,在c7-client主机上创建了一个空文件rsync.txt,并设置了权限和ownership,然后同步至C7主机。可以发现同步后,文件的权限、所有权以及mtime都发生了改变。

[root@c7-client ~]# ls -l rsync.txt
-rw-rw-rw-. haimianbb haimianbb Dec : rsync.txt
[root@c7-client ~]# rsync -v rsync.txt root@192.168.17.7:/tmp/rsync.txt
rsync.txt sent bytes received bytes 236.00 bytes/sec
total size is speedup is 0.00
[root@C7 ~]# ls -l /tmp/rsync.txt
-rw-r--r-- root root Dec : /tmp/rsync.txt

当我们使用了-togp选项之后,文件的权限、mtime和所有权都保持了。

[root@c7-client ~]# rsync -vtogp rsync.txt root@192.168.17.7:/tmp/rsync.txt
rsync.txt sent bytes received bytes 296.00 bytes/sec
total size is speedup is 0.00
[root@C7 ~]# ls -l /tmp/rsync.txt
-rw-rw-rw- haimianbb haimianbb Dec : /tmp/rsync.txt

-D:等同于--devices和--specials的结合,用于同步字符设备、块设备以及特殊文件(socket)。

-l, --links:当遇到字符链接的时候,在远程主机上创建相同的字符链接文件。

默认情况下,字符链接文件是非普通文件,会被rsync跳过。

[root@C7 tmp]# cat /tmp/name.txt
zhangwenlong
[root@C7 tmp]# ln -s /tmp/name.txt /tmp/name.link
[root@C7 tmp]# ls -l name.link
lrwxrwxrwx root root Dec : name.link -> /tmp/name.txt
[root@C7 tmp]# rsync -v name.link /root/name.rsync
skipping non-regular file "name.link" sent bytes received bytes 194.00 bytes/sec
total size is speedup is 0.13

使用-l选项就可以同步字符链接文件了,同步后的文件也是一个字符链接文件。

[root@C7 tmp]# rsync -vl name.link /root/name.rsync
name.link -> /tmp/name.txt sent bytes received bytes 158.00 bytes/sec
total size is speedup is 0.16
[root@C7 tmp]# ls -l /root/name.rsync
lrwxrwxrwx root root Dec : /root/name.rsync -> /tmp/name.txt
[root@C7 tmp]# cat /root/name.rsync
zhangwenlong

-z, --compress:传输之前是否对数据进行压缩。可以留意到压缩后,发送的字节数降低了。

[root@C7 tmp]# rsync -v /etc/inittab /tmp/inittab
inittab sent bytes received bytes ,250.00 bytes/sec
total size is speedup is 0.82
[root@C7 tmp]# rsync -vz /etc/inittab /tmp/inittab
inittab sent bytes received bytes 798.00 bytes/sec
total size is speedup is 1.28

-R, --relative:使用相对路径。意味着会将命令行中完整的路径名称发送给远程主机,而不是只发送最后一部分的文件名。

我们先来看一下默认情况下的行为。复制/foo/bar/baz.c到/tmp/目录下的时候,仅会在/tmp/目录下创建baz.c文件。(从-v结果来看,应理解为仅将源文件“/foo/bar/baz.c”中的最后一部分“baz.c”加入了文件列表)

[root@C7 ~]# rsync -v /foo/bar/baz.c /tmp/
baz.c sent bytes received bytes 226.00 bytes/sec
total size is speedup is 0.00

如果增加了-R选项。则是在/tmp/目录下创建了完整的目录结构。这是因为-R选项使得发送端rsync将整个源文件路径“/foo/bar/baz.c”加入了文件列表。

[root@C7 ~]# rsync -vR /foo/bar/baz.c /tmp/
/foo/
/foo/bar/
/foo/bar/baz.c sent bytes received bytes 338.00 bytes/sec
total size is speedup is 0.00
[root@C7 ~]# tree /tmp/foo/
/tmp/foo/
└── bar
└── baz.c directory, file

像“foo/”和“foo/bar/”这种额外的路径元素,我们就称其为隐式目录(implied  directories)。如果相对路径涉及到字符链接的话,可能会有特殊情况,要看一下man手册。

有的时候你可能只希望在接收端创建部分源文件路径,那么可以在源文件路径中插入一个“.”和“/”。

[root@C7 tmp]# rsync -vR /foo/./bar/baz.c /tmp/
bar/
bar/baz.c sent bytes received bytes 276.00 bytes/sec
total size is speedup is 0.00

这样子相对路径就是从bar开始的了。

--size-only:修改rsync默认的quick check算法,仅检查两端文件大小。个人建议不要带上该选项,虽然检查的复杂度降低了,可能会提升性能,但是可能出现内容不同的文件没得到正确的同步,在特定的环境下可能造成严重的后果。

就像这个例子中所示,1.txt和2.txt明明文件内容不一致,却因为--size-only选项使得它们没有被同步。

[root@C7 tmp]# ls -l {,}.txt
-rw-r--r-- root root Dec : .txt
-rw-r--r-- root root Dec : .txt
[root@C7 tmp]# diff {,}.txt
1c1
<
---
>
[root@C7 tmp]# rsync -v --size-only {,}.txt sent bytes received bytes 102.00 bytes/sec
total size is speedup is 0.18
[root@C7 tmp]# diff {,}.txt
1c1
<
---
>

-c, --checksum:修改rsync默认的quick check算法,通过检验码的方式检查两端的文件内容是否一致,生成校验码会引起两端产生大量的磁盘I/O,因此一般是不会启用该选项

-u, --update:如果目标文件存在且mtime新于源文件的话,则跳过。如果目标文件存在且mtime等于源文件的话,则判断size,size同则不同步,size不同则同步。该选项是传输规则,并不是exclude,因此不会影响文件进入文件列表,因此不会影响目标文件上的删除操作。

-d, --dirs:用于拷贝目录本身,但是不会拷贝目录下的文件。有别于-r, --recursive。但是如果源文件是以“.”或者斜杠结尾的话,那么还是会将目录下的内容拷贝至目标文件。如果-r和-d同时使用的话,那么-r优先。

--max-size=SIZE:限制传输的文件的最大size。可以带上单位后缀“K、KiB、M、MiB、G、GiB”,这是以1024为乘数,如果想要以1000为乘数的话,则使用“KB、MB和GB”。大小写均可。

--min-size=SIZE:限制传输的文件的最小size。其他说明类似上面的--max-size,避免传输较小的文件或者垃圾文件。

--exclude=PATTERN:用于排除文件,被排除的文件不会被同步。涉及到man手册中的过滤规则(FILTER RULE)。后面会详述。

--exclude-from=FILE:排除文件,即当需要排除的PATTERN较多的时候,可以将每一个PATTERN都写入该文件中,每个PATTERN占一行。空行以及以“#”或者“;”开头的行会被忽略。FILE为“-”表示读取STDIN(标准输入)。

--delete:删除接收端中不存在于发送端的额外的文件,仅作用于那些已经同步了的目录。后面会详述。

-b, --backup:当目标文件已经存在的时候,同步操作即将覆盖或者同步操作(--delete)即将删除目标文件的时候,对其进行备份。

[root@C7 tmp]# rsync -vb /foo/bar/baz.c /tmp/
baz.c sent bytes received bytes 226.00 bytes/sec
total size is speedup is 0.00
[root@C7 tmp]# ls -l /tmp/baz.c*
-rw-r--r-- root root Dec : /tmp/baz.c
-rw-r--r-- root root Dec : /tmp/baz.c~

即便反复执行,备份文件的文件名依然是“baz.c~”。

--backup-dir=DIR:指定备份文件的目录。默认的备份目录是在目标文件的当前目录。

若备份目录不存在,则会自动创建,并回显。

[root@C7 tmp]# rsync -vb --backup-dir=/tmp/back/ /foo/bar/baz.c /tmp/
(new) backup_dir is /tmp/back
baz.c sent bytes received bytes 294.00 bytes/sec
total size is speedup is 0.00

备份文件会是/tmp/back/baz.c,它不带后缀,反复执行也依然是该文件。

--suffix=SUFFIX:指定备份文件的后缀。默认的备份后缀是“~”。

[root@C7 tmp]# rsync -vb --suffix=alongdidi /foo/bar/baz.c /tmp/
baz.c sent bytes received bytes 226.00 bytes/sec
total size is speedup is 0.00

备份文件是/tmp/baz.calongdidi,反复执行的话也依然是该文件。

rsync的备份机制似乎不能递增,只能反复覆盖,感觉并没有什么卵用。

-e, --rsh=COMMAND:用于选择一个远程shell程序,现在所使用的一般都是SSH了(以前是RSH,但是RSH没有加密功能),所以一般是用于指定SSH的选项。

主要用于指定ssh的参数,以及用于临时daemon。

-e 'ssh -p 2234'
-e 'ssh -o "ProxyCommand nohup ssh firewall nc -w1 %h %p"'

--port=PORT:如果使用的rsync daemon的工作方式的时候,用于指定端口号,默认是873。

--password-file=FILE:用于指定rsync认证的密码文件。非SSH认证的密码。FILE可以为“-”表示读取STDIN。如果密码文件是全局可读,或者以root用户运行rsync但是密码文件的ownership不是root的话,那么rsync会退出。

--existing, --ignore-non-existing:告诉rsync,只更新目标文件中已存在的文件。

--ignore-existing:告诉rsync,只更新目标文件中不存在的文件。

创建了2个目录,目录结构如下。默认情况下,将a目录同步至b目录的话,除了会将a.txt加入文件列表中以外,还会将{1,2,3}.txt也加入文件列表中。

[root@C7 tmp]# tree {a,b}
a
├── .txt
├── .txt
├── .txt
└── a.txt
b
├── .txt
├── .txt
├── .txt
└── b.txt directories, files

如果我们只想同步接收端已存在的文件的话,则使用--existing选项。

[root@C7 tmp]# rsync -rv --existing a/ b/
sending incremental file list
.txt
.txt
.txt sent bytes received bytes 616.00 bytes/sec
total size is speedup is 0.00

如果我们只想同步接收端不存在的文件的话,则使用--ignore-existing选项。

[root@C7 tmp]# rsync -rv --ignore-existing a/ b/
sending incremental file list
a.txt sent bytes received bytes 384.00 bytes/sec
total size is speedup is 0.00

--existing选项可以和--ignore-existing选项结合使用,结合使用的情况下不会同步任何文件,一般用于配合--delete选项实现在不传输任何数据的情况下,仅删除接收端的额外文件。

可以看一下单独使用--delete和结合使用的区别。

[root@C7 tmp]# rsync -rv --delete a/ b/
sending incremental file list
deleting b.txt
.txt
.txt
.txt
a.txt sent bytes received bytes 750.00 bytes/sec
total size is speedup is 0.00 [root@C7 tmp]# rsync -rv --existing --ignore-existing --delete a/ b/
sending incremental file list
deleting b.txt sent bytes received bytes 270.00 bytes/sec
total size is speedup is 0.00

--remove-source-files:源文件如果同步成功,则将其删除。

[root@C7 tmp]# tree {a,b}
a
├── .txt
├── .txt
├── .txt
└── a.txt
b
├── .txt
├── .txt
├── .txt
└── b.txt directories, files
[root@C7 tmp]# rsync -rv --remove-source-files a/ b/
sending incremental file list
.txt
.txt
.txt
a.txt sent bytes received bytes 796.00 bytes/sec
total size is speedup is 0.00
[root@C7 tmp]# tree {a,b}
a
b
├── .txt
├── .txt
├── .txt
├── a.txt
└── b.txt directories, files

rsync的include/exclude模式

--exclude=PATTERN:rsync通过该选项来排除所不需要同步的文件。它是--filter选项的一种简写形式。

一个--exclude选项只能排除一个模式,如果要排除多个模式的话,可以在命令行中书写多次--exclude选项,或者将模式逐行写入文件中,然后使用--exclude-from引用该模式文件。

简单的示例如下。

[root@C7 tmp]# tree {a,b}
a
├── .txt
├── .txt
├── .txt
└── a.txt
b
├── .txt
├── .txt
└── .txt directories, files
[root@C7 tmp]# rsync -rv --exclude=a.txt a/ b/
sending incremental file list
.txt
.txt
.txt sent bytes received bytes 576.00 bytes/sec
total size is speedup is 0.00
[root@C7 tmp]# rsync -rv --exclude=a.txt a b/
sending incremental file list
a/
a/.txt
a/.txt
a/.txt sent bytes received bytes 614.00 bytes/sec
total size is speedup is 0.00

第二次同步的时候,如果不加--exclude选项,那么会同步以下:

  • a/
  • a/1.txt
  • a/2.txt
  • a/3.txt
  • a/a.txt

我们排除的模式是a.txt,模式没有以“/”开头或者结尾,那么只要传输整个名称中某个部分包含了a.txt,就会生效。因此,a/a.txt也被排除掉了。

排除的时候,模式的书写其实是一个难点。在man手册中有比较详细的描述,涉及到

  • 源文件如果是个目录,那么末尾是否带上斜线。
  • 是否使用相对目录的选项--relative。
  • 什么是传输中的根目录。
  • 模式是否以“/”开头。若是则涉及到锚定传输根的概念。
  • 模式是否以“/”结尾。若是则判定为目录。
  • 模式是否是无限制(unqualified)的,例如“foo”或者上述的“a.txt”。无限制指的是没有以“/”开头或者结尾。若是则匹配的灵活度是很大的。
  • 等等。

这个需要大家自行看一下man手册以及自己反复敲命令体验一下,一般是带上-avn选项来测试。

再来几个示例,首先我们先看一下目录a的层级结构。

[root@C7 tmp]# tree a/
a/
├── .txt
├── .txt
├── .txt
├── a.txt
├── index.php
└── public
└── index.php directory, files

然后我们以测试的形式,同步a目录至b目录,注意此时同步的源目录a的末尾带上了斜线。首先我们看一下不带排除选项的话,会同步哪些文件。

[root@C7 tmp]# rsync -avn a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
index.php
public/
public/index.php sent bytes received bytes 546.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

源目录带上斜线,并且没有-R选项,这时候就已经确定了传输根了。即这个示例中的传输根是a/下开始。而不是a目录本身开始,更不是/tmp/a(案例中我的PWD目录是/tmp)开始。

这时候我们排除无限制的index.php。

[root@C7 tmp]# rsync -avn --exclude=index.php a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
public/ sent bytes received bytes 420.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

无限制的匹配范围很大,只要整棵树/整个名称中包含了模式,就会生效。因此index.php和public/index.php都会排除掉。

接下来我们来一个有限制的,排除掉传输根下的index.php。

[root@C7 tmp]# rsync -avn --exclude=/index.php a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
public/
public/index.php

排除模式不改变,通过修改源目录末尾的斜线,从而改变了传输根,再来看看变化。

[root@C7 tmp]# rsync -avn --exclude=/index.php a b/
sending incremental file list
a/
a/.txt
a/.txt
a/.txt
a/a.txt
a/index.php
a/public/
a/public/index.php sent bytes received bytes 572.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

这个时候想要再排除a目录下的index.php,就得输入--exclude=a/index.php或者--exclude=/a/index.php了。

如果模式末尾带上斜线,则表示这个模式匹配到的,一定得是一个目录。因为index.php不是目录,所以不会被排除了。

[root@C7 tmp]# rsync -avn --exclude=index.php/ a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
index.php
public/
public/index.php sent bytes received bytes 546.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

--exclude用于排除,而--include用于包含。当同一个文件,既被排除又被包含的时候,要看哪个选项放在前面。先遇到先生效。

[root@C7 tmp]# rsync -avn --exclude=index.php --include=index.php a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
public/
public/test.txt sent bytes received bytes 478.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)
[root@C7 tmp]# rsync -avn --include=index.php --exclude=index.php a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
index.php
public/
public/index.php
public/test.txt sent bytes received bytes 610.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

当include和exclude规则同时使用且使用了递归选项(-r或者-a)的时候,如果排除了某个文件的父目录(或者爷爷目录等更高层的目录),那么即便该文件被包含了并且include的规则放在最前面,该文件也仍然不会被同步。

[root@C7 tmp]# rsync -avn --include=public/index.php --exclude=public/ a/ b/
sending incremental file list
./
.txt
.txt
.txt
a.txt
index.php sent bytes received bytes 392.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

rsync的--delete选项

选项与示例中我们已经解释了--delete选项的作用,在上文--existing和--ignore-existing结合使用的示例中我们也初次使用了它。

根据工作方式,即可删除本地主机上的文件,也可以删除目标主机上的文件。如果以一个空目录作为源文件的话,则会清空目标目录。

当--delete选项和--exclude选项同时使用的时候,被排除的文件不会被删除。我们来验证一下。

文件层级结构如下。

[root@C7 tmp]# tree test{,}
test1
├── .txt
├── .txt
└── .txt
test2
├── .txt
├── .txt
├── .txt
├── apple.jpg
├── icon.jpg
├── my.cnf
├── mysqld.log
└── pear.jpg directories, files

仅删除不排除的情况。

[root@C7 tmp]# rsync -rvn --delete test1/ test2/
sending incremental file list
deleting pear.jpg
deleting mysqld.log
deleting my.cnf
deleting icon.jpg
deleting apple.jpg
.txt
.txt
.txt sent bytes received bytes 362.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

增加排除的情况。可见被排除的模式,就不再会被删除了。

[root@C7 tmp]# rsync -rvn --delete --exclude=*.jpg test1/ test2/
sending incremental file list
deleting mysqld.log
deleting my.cnf
.txt
.txt
.txt sent bytes received bytes 288.00 bytes/sec
total size is speedup is 0.00 (DRY RUN)

验证无误,接下来我们来理解一下这是为什么。

rsync同步的过程中,发送端将需要传输的文件放入文件列表中(文件列表中的每一行我们称为条目),该文件列表会被传输给接收端。接收端的generator进程对每个条目计算数据块校验码(一个文件可以由多个数据块组成)并返回给发送端,发送端根据数据块校验码来判断哪些数据块应该被传输,这样就实现了rsync的增量传输功能——仅传输文件中不同的数据块,而非整个文件。

--exclude本质是一种筛选规则,如果某个文件被其指定了,那么该文件在加入文件列表的时候,会被标记为隐藏(hide)。

--delete删除的时间点是generator进程处理文件列表时、生成数据块校验码之前,这样子的好处是被--delete所删除的文件就不需要再去计算数据块校验码了。

小结一下:--exclude是在发送端创建文件列表的时候起作用;--delete是在文件列表已经生成并发送往接收端,在接收端才起作用。因此--exclude先于--delete。此时我们可能会认为,如果某个条目带有hide标记,则接收端会认为其不存在于发送端而将其删除,但是rsync却不是这么做。rsync还会将被--exclude的文件标记为保护(protect),防止其结合--delete使用的时候被误删除,如果确实要删除的话,可以使用--delete-excluded。

结语

本文目前只涉及到rsync的本地和远程shell的使用。daemon和临时daemon暂时没有涉及,如果将来在工作中有使用到的话可能会补上。已经在rsync上使用了较多的时间,暂时先告一段落,再次感谢博主:骏马金龙。

工作中主要是使用了rsync作为PHP代码部署的工具。结合排除功能与shell脚本,应该是可以满足一般的小企业了。

rsync基础的更多相关文章

  1. rsync的man手册(未完成)

    本文是man rsync的官方手册译文,版本是3.1.2. 本文没打算翻译每个option,常用的option已经在另一篇文章rsync基础中有描述. 一开始的翻译过程比较顺畅,越到后面越难以理解,侧 ...

  2. rsync+inotify同步备份文件

    前言 rsync作用:man rsync可以看到解释为a fast, versatile, remote (and local) file-copying tool,主要进行文件的同步. inotif ...

  3. Linux基础命令介绍七:网络传输与安全 wget curl rsync iptables

    本篇接着介绍网络相关命令:wget 文件下载工具.curl 网络数据传输工具.rsync 文件传输工具等. 本篇接着介绍网络相关命令 1.wget 文件下载工具 wget [option]... [U ...

  4. Linux基础学习-数据备份工具Rsync

    数据备份工具rsync 作为一个系统管理员,数据备份是非常重要的,如果没有做好备份策略,磁盘损坏了,那么你的数据将全部丢失,所以在日常的维护工作中,一定要时刻牢记给数据做备份. rsync不仅可以可以 ...

  5. 【基础】:Rsync数据同步工具

    第二十一节 Rsync数据同步工具 1.1 Rsync介绍 1.1.1 什么是Rsync? 1.1.2 Rsync简介 1.3 Rsync的特性 1.1.4 Rsync的企业工作场景说明 1.2 Rs ...

  6. Git基础操作

    配置秘钥 1.检查本机有没有秘钥 检查~/.ssh看看是否有名为d_rsa.pub和id_dsa.pub的2个文件. $ ~/.sshbash: /c/Users/lenovo/.ssh: Is a ...

  7. Linux基础精华

    Linux基础精华 (继续跟新中...) 常用命令: Linux shell 环境 让你提升命令行效 率的 Bash 快捷键 [完整版] 设置你自己的liux alias Linux的Find使用 L ...

  8. centos rsync安装配置

    安装 1 yum -y install rsync ---------------------服务器安装------------------------------- 创建基础配置文件 1 2 3 4 ...

  9. linux入门基础_centos(一)--基础命令和概念

    闲来无事干,看看2014自己整理的一些学习笔记.独乐了不如众乐乐吗! 贴出来和大家分享一下,由于篇幅比较长,分成几篇发布吧,由于是学习笔记,可能有些地方写的不是很正确或者说不详细,或者你会看到上面的课 ...

随机推荐

  1. 「Vue」父子组件之间的传值及调用方法

    a.父组件向子组件传值data(){},props数据区别data中的数据可读可写,是自己的数据props是个数组,中的数据是父组件传递过来的,只读不能写<login :dmsg='msg'&g ...

  2. 20181111 Quartz(慕课网)

    Quartz体系结构 三个核心概念 调度器 任务 触发器 重要组成 Job JobBuilder JobDetail JobStore Trigger TriggerBuilder ThreadPoo ...

  3. 20181108 Apache Commons Lang

    工具类 org.apache.commons.lang3 AnnotationUtils ArchUtils ArrayUtils BooleanUtils CharSetUtils CharUtil ...

  4. angularJs的各种服务和指令的使用场景

    $location服务,获取页面跳转带的参数 比如说页面是这样的  localhost:9102/admin/goods.html#?id=123   如何获取这个id=123的值呢?????(注意: ...

  5. java精确除法运算(BigDecimal)

    除法运算的函数定义如下 BigDecimal.divide(BigDecimal divisor, int scale, RoundingMode roundingMode) ; scale为小数位数 ...

  6. 《高性能MySQL》——第一章MySQL的架构与历史

    1.可以使用SHOW TABLE STATUS查询表的相关信息. 2.默认存储引擎是InnoDB,如果没有什么很特殊的要求,InnoDB引擎是我们最好的选择. 3.mysql的infobright引擎 ...

  7. spring框架学习(三)spring与junit整合测试

    package cn.mf.b_test; import javax.annotation.Resource; import org.junit.Test; import org.junit.runn ...

  8. 怎样提高WebService的性能

    服务器端WebService程序: using System.Runtime.Serialization.Formatters.Binary; using System.IO; using Syste ...

  9. UVALive 6467

    题目链接 : http://acm.sdibt.edu.cn/vjudge/contest/view.action?cid=2186#problem/C 题意:对于斐波那契数列,每个数都mod m , ...

  10. 洛谷 P4838 P哥破解密码 题解

    矩阵乘法 + 快速幂优化递推: 看到这个题目我们不难想到递推,题干中说3个连续的A出现在序列中是不合法的,所以可以分为三种情况: (1):序列前只有一个A,如:BA,BBA,BABA. (2):序列前 ...