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脚本,应该是可以满足一般的小企业了。

  • 相关阅读:
    【转】 java中Class对象详解和类名.class, class.forName(), getClass()区别
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    107. Binary Tree Level Order Traversal II
    109. Convert Sorted List to Binary Search Tree
    108. Convert Sorted Array to Binary Search Tree
    110. Balanced Binary Tree
    STL容器迭代器失效问题讨论
    113. Path Sum II
    112. Path Sum
  • 原文地址:https://www.cnblogs.com/alongdidi/p/rsync.html
Copyright © 2011-2022 走看看