zoukankan      html  css  js  c++  java
  • rsync基础

    参考资料:骏马金龙的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/1.txt 
    /tmp/1.txt: empty
    [root@C7 ~]# rsync /etc/fstab /etc/inittab /tmp/1.txt
    ERROR: destination must be a directory when copying more than 1 file
    rsync error: errors selecting input/output files, dirs (code 3) at main.c(623) [Receiver=3.1.2]

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

    [root@c7-client ~]# rsync /etc/fstab 
    -rw-r--r--            487 2018/12/18 11:46:20 fstab
    [root@c7-client ~]# rsync /etc/ssh/
    drwxr-xr-x            225 2018/12/18 12:04:37 .
    -rw-r--r--        581,843 2018/04/11 12:21:29 moduli
    -rw-r--r--          2,276 2018/04/11 12:21:29 ssh_config
    -rw-r-----            227 2018/12/18 12:04:37 ssh_host_ecdsa_key
    -rw-r--r--            162 2018/12/18 12:04:37 ssh_host_ecdsa_key.pub
    -rw-r-----            387 2018/12/18 12:04:37 ssh_host_ed25519_key
    -rw-r--r--             82 2018/12/18 12:04:37 ssh_host_ed25519_key.pub
    -rw-r-----          1,679 2018/12/18 12:04:35 ssh_host_rsa_key
    -rw-r--r--            382 2018/12/18 12:04:35 ssh_host_rsa_key.pub
    -rw-------          3,907 2018/04/11 12:21:29 sshd_config
    [root@c7-client ~]# rsync root@192.168.17.7:/etc/fstab
    root@192.168.17.7's password: 
    -rw-r--r--            465 2018/09/27 15:49:45 fstab
    [root@c7-client ~]# rsync root@192.168.17.7:/etc/ssh/
    root@192.168.17.7's password: 
    drwxr-xr-x            225 2018/09/27 17:28:23 .
    -rw-r--r--        581,843 2018/04/11 12:21:29 moduli
    -rw-r--r--          2,276 2018/04/11 12:21:29 ssh_config
    -rw-r-----            227 2018/09/27 16:02:33 ssh_host_ecdsa_key
    -rw-r--r--            162 2018/09/27 16:02:33 ssh_host_ecdsa_key.pub
    -rw-r-----            387 2018/09/27 16:02:33 ssh_host_ed25519_key
    -rw-r--r--             82 2018/09/27 16:02:33 ssh_host_ed25519_key.pub
    -rw-r-----          1,679 2018/09/27 16:02:33 ssh_host_rsa_key
    -rw-r--r--            382 2018/09/27 16:02:33 ssh_host_rsa_key.pub
    -rw-------          3,905 2018/09/27 17:28:23 sshd_config

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

    [root@c7-client ~]# rsync root@192.168.17.7:/etc/fstab
    -rw-r--r--            465 2018/09/27 15:49:45 fstab

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

    [root@c7-client ~]# rsync /etc/fstab /tmp/
    [root@c7-client ~]# ls -l /etc/fstab /tmp/fstab 
    -rw-r--r--. 1 root root 487 Dec 18 11:46 /etc/fstab
    -rw-r--r--. 1 root root 487 Dec 19 19:04 /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{1,2,3}.txt
    [root@c7-client ~]# rsync -r testdir/ root@192.168.17.7:/root/
    [root@C7 ~]# ls -l /root/rsync{1,2,3}.txt
    -rw-r--r-- 1 root root 0 Dec 19 19:17 /root/rsync1.txt
    -rw-r--r-- 1 root root 0 Dec 19 19:17 /root/rsync2.txt
    -rw-r--r-- 1 root root 0 Dec 19 19:17 /root/rsync3.txt
    [root@c7-client ~]# rsync -r root@192.168.17.7:/root/rrr .
    [root@c7-client ~]# ls -l rrr/
    total 0
    -rw-r--r--. 1 root root 0 Dec 19 19:19 l.txt
    -rw-r--r--. 1 root root 0 Dec 19 19:19 w.txt
    -rw-r--r--. 1 root root 0 Dec 19 19:19 z.txt

     

    选项与示例

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

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

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

    782448  63%  110.64kB/s    0:00:04

    -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 16 bytes  received 12 bytes  56.00 bytes/sec
    total size is 0  speedup is 0.00
    [root@C7 tmp]# rsync -v /foo /tmp/
    skipping directory foo
    
    sent 16 bytes  received 12 bytes  56.00 bytes/sec
    total size is 0  speedup is 0.00

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

    [root@C7 tmp]# rsync -rv /foo/ /tmp/
    sending incremental file list
    bar/baz.c
    
    sent 131 bytes  received 36 bytes  334.00 bytes/sec
    total size is 0  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-. 1 haimianbb haimianbb 0 Dec 25 10:06 rsync.txt
    [root@c7-client ~]# rsync -v rsync.txt root@192.168.17.7:/tmp/rsync.txt
    rsync.txt
    
    sent 83 bytes  received 35 bytes  236.00 bytes/sec
    total size is 0  speedup is 0.00
    [root@C7 ~]# ls -l /tmp/rsync.txt 
    -rw-r--r-- 1 root root 0 Dec 25 10:12 /tmp/rsync.txt

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

    [root@c7-client ~]# rsync -vtogp rsync.txt root@192.168.17.7:/tmp/rsync.txt
    rsync.txt
    
    sent 113 bytes  received 35 bytes  296.00 bytes/sec
    total size is 0  speedup is 0.00
    [root@C7 ~]# ls -l /tmp/rsync.txt
    -rw-rw-rw- 1 haimianbb haimianbb 0 Dec 25 10:06 /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 1 root root 13 Dec 25 17:32 name.link -> /tmp/name.txt
    [root@C7 tmp]# rsync -v name.link /root/name.rsync
    skipping non-regular file "name.link"
    
    sent 43 bytes  received 54 bytes  194.00 bytes/sec
    total size is 13  speedup is 0.13

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

    [root@C7 tmp]# rsync -vl name.link /root/name.rsync
    name.link -> /tmp/name.txt
    
    sent 60 bytes  received 19 bytes  158.00 bytes/sec
    total size is 13  speedup is 0.16
    [root@C7 tmp]# ls -l /root/name.rsync 
    lrwxrwxrwx 1 root root 13 Dec 25 17:35 /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 590 bytes  received 35 bytes  1,250.00 bytes/sec
    total size is 511  speedup is 0.82
    [root@C7 tmp]# rsync -vz /etc/inittab /tmp/inittab
    inittab
    
    sent 364 bytes  received 35 bytes  798.00 bytes/sec
    total size is 511  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 78 bytes  received 35 bytes  226.00 bytes/sec
    total size is 0  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 128 bytes  received 41 bytes  338.00 bytes/sec
    total size is 0  speedup is 0.00
    [root@C7 ~]# tree /tmp/foo/
    /tmp/foo/
    └── bar
        └── baz.c
    
    1 directory, 1 file

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

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

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

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

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

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

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

    -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 78 bytes  received 35 bytes  226.00 bytes/sec
    total size is 0  speedup is 0.00
    [root@C7 tmp]# ls -l /tmp/baz.c*
    -rw-r--r-- 1 root root 0 Dec 21 17:28 /tmp/baz.c
    -rw-r--r-- 1 root root 0 Dec 21 17:28 /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 78 bytes  received 69 bytes  294.00 bytes/sec
    total size is 0  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 78 bytes  received 35 bytes  226.00 bytes/sec
    total size is 0  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
    ├── 1.txt
    ├── 2.txt
    ├── 3.txt
    └── a.txt
    b
    ├── 1.txt
    ├── 2.txt
    ├── 3.txt
    └── b.txt
    
    0 directories, 8 files

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

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

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

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

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

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

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

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

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

     

    rsync的include/exclude模式

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

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

    简单的示例如下。

    [root@C7 tmp]# tree {a,b}
    a
    ├── 1.txt
    ├── 2.txt
    ├── 3.txt
    └── a.txt
    b
    ├── 1.txt
    ├── 2.txt
    └── 3.txt
    
    0 directories, 7 files
    [root@C7 tmp]# rsync -rv --exclude=a.txt a/ b/
    sending incremental file list
    1.txt
    2.txt
    3.txt
    
    sent 215 bytes  received 73 bytes  576.00 bytes/sec
    total size is 0  speedup is 0.00
    [root@C7 tmp]# rsync -rv --exclude=a.txt a b/
    sending incremental file list
    a/
    a/1.txt
    a/2.txt
    a/3.txt
    
    sent 230 bytes  received 77 bytes  614.00 bytes/sec
    total size is 0  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/
    ├── 1.txt
    ├── 2.txt
    ├── 3.txt
    ├── a.txt
    ├── index.php
    └── public
        └── index.php
    
    1 directory, 6 files

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

    [root@C7 tmp]# rsync -avn a/ b/
    sending incremental file list
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    index.php
    public/
    public/index.php
    
    sent 232 bytes  received 41 bytes  546.00 bytes/sec
    total size is 0  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
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    public/
    
    sent 175 bytes  received 35 bytes  420.00 bytes/sec
    total size is 0  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
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    public/
    public/index.php

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

    [root@C7 tmp]# rsync -avn --exclude=/index.php a b/
    sending incremental file list
    a/
    a/1.txt
    a/2.txt
    a/3.txt
    a/a.txt
    a/index.php
    a/public/
    a/public/index.php
    
    sent 244 bytes  received 42 bytes  572.00 bytes/sec
    total size is 0  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
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    index.php
    public/
    public/index.php
    
    sent 232 bytes  received 41 bytes  546.00 bytes/sec
    total size is 0  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
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    public/
    public/test.txt
    
    sent 201 bytes  received 38 bytes  478.00 bytes/sec
    total size is 0  speedup is 0.00 (DRY RUN)
    [root@C7 tmp]# rsync -avn --include=index.php --exclude=index.php a/ b/
    sending incremental file list
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    index.php
    public/
    public/index.php
    public/test.txt
    
    sent 261 bytes  received 44 bytes  610.00 bytes/sec
    total size is 0  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
    ./
    1.txt
    2.txt
    3.txt
    a.txt
    index.php
    
    sent 162 bytes  received 34 bytes  392.00 bytes/sec
    total size is 0  speedup is 0.00 (DRY RUN)

     

    rsync的--delete选项

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

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

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

    文件层级结构如下。

    [root@C7 tmp]# tree test{1,2}
    test1
    ├── 1.txt
    ├── 2.txt
    └── 3.txt
    test2
    ├── 1.txt
    ├── 2.txt
    ├── 3.txt
    ├── apple.jpg
    ├── icon.jpg
    ├── my.cnf
    ├── mysqld.log
    └── pear.jpg
    
    0 directories, 11 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
    1.txt
    2.txt
    3.txt
    
    sent 99 bytes  received 82 bytes  362.00 bytes/sec
    total size is 0  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
    1.txt
    2.txt
    3.txt
    
    sent 99 bytes  received 45 bytes  288.00 bytes/sec
    total size is 0  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脚本,应该是可以满足一般的小企业了。

  • 相关阅读:
    jquery Flexigrid只选择一行,增加双击事件,获取数据库ID
    [工具库]JOJSONBuilder工具类——一键把多个bean对象数据转换为JSON格式数据
    java 观察者模式
    [工具库]JOXMLBuilder工具类——一键把多个bean对象数据转换为XML格式数据
    JVM原理
    WEB项目的分层结构
    一刻钟精通正则表达式
    [Java]Stack栈和Heap堆的区别(终结篇)[转]
    [java]二、八、十、十六进制之间的转换
    java 适配器模式
  • 原文地址:https://www.cnblogs.com/alongdidi/p/rsync.html
Copyright © 2011-2022 走看看