rsync是一个很强大的文件拷贝/备份工具,是cp,scp,cpio,find等命令的综合体.大部分需要这些工具用管道组合才能实现的功能,可以通过rsync强大的一行命令解决.rsync的学习之路分为三个阶段:1.基本的命令行与常用选项
2.远程服务配置
3.文件过滤功能
阶段1
根据man rsync的手册上的介绍,rsync一共有最多八种功能,但其实也就是个噱头,总的来说是两类功能
1.本地拷贝,命令行: rsync [OPTION]... src [src]... dest
比如,把/etc目录下的*.conf文件拷贝到dir目录下:
rsync -avzP /etc/*.conf ./
这条命令基本上相当于cp,但还有一些其它的cp做不到的玩法
2.远程拷贝.rsync支持"本地->远程","远程->本地"双方拷贝,不支持"远程->远程"拷贝.rsync的网络功能通过两种方式:ssh服务和rsync --daemon服务.命令行有三种形式(只介绍本地->远程模式):
rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST 这种形式和scp很像,大家应该很熟悉,比如
rsync avz *.c foo:/home/user1/src/
把当前目录下的c语言拷贝到foo主机下的src目录下.在输入命令后,会要求你输入密码.当然不带user@时是使用当前用户.这个逻辑与scp和rcp相同.这种模式就是通过ssh服务实现的
rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST 这种形式跟第一种相比就是多了个:,但意义不同.需要HOST端的rsync服务支持.比如:
rsync avz *.c foo::src/
把当前目录下的c语言拷贝到foo主机下的src标签定义的目录下.主机与用户名格式不变,但此处的src不同于上.此种的src是服务端rsyncd.conf里定义的标签名.该标签定义了目录名,各种权限等,比如一个典型的:
[src]
path = /home/user1/src
comment = ftp export area 定义了src这个tag的路径和介绍.其它还有user,密码文件,权限等属性可以定义
rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST 这种形式同上,也需要HOST商的rsync的服务支持.这是rsync特有的一种形式,其特点在于可以查看远程的文件有什么而不一定要拷贝.查看的命令即是只要一个参数, 比如:
[work@10.81.52.135]~>$ rsync rsync://10.81.47.94
data It's my fucking data!
etc It's etc
[work@10.81.52.135]~>$ rsync rsync://10.81.47.94/data
Password:
@ERROR: auth failed on module data
rsync: connection unexpectedly closed (0 bytes received so far) [receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(359)
[work@10.81.52.135]~>$ rsync rsync://10.81.47.94/data --password-file=pss
drwxrwxrwx 4096 2012/04/08 07:26:34 .
-rw------- 4522 2012/04/01 20:44:45 .bash_history
-rw-r--r-- 304 2010/08/19 19:54:33 .bash_logout
-rw-r--r-- 1620 2012/04/01 12:04:49 .bash_profile
-rw-r--r-- 124 2010/08/19 19:54:33 .bashrc
drwx------ 4096 2010/09/15 15:24:14 .bssh
-rw-r--r-- 383 2010/08/19 19:54:33 .emacs
drwx------ 4096 2010/09/15 15:24:14 .ssh
-rw------- 7962 2012/04/01 15:34:05 .viminfo
-rw-r--r-- 658 2010/08/19 19:54:33 .zshrc
-rw-rw-r-- 91678576 2012/03/29 17:18:54 acd_ims.tar.gz
drwxrwxrwx 4096 2012/04/01 14:06:32 creampie
-rw-rw-r-- 8 2012/04/08 07:26:34 ff
drwxrwxr-x 4096 2010/09/15 15:23:28 opbin
drwxrwxr-x 4096 2010/09/15 15:23:10 opdir
drwxrwxrwx 4096 2012/04/08 05:43:34 ss
drwxrwxrwx 4096 2012/04/01 15:25:02 wx
看上去是不是很像ftp的效果.只是rsync的查看是一次性的,不支持命令行二次操作.
现在,我们来看看rsync的选项.rsync继承了unix一贯的man死人的风格,选项多的令人发指.不信可以直接输入rsync回车.但一般常用的就以下几个:
-H 保留源文件的硬链接文件
-r 递归模式,包含目录及子目录的所有信息
-z 在传输文件的同时进行压缩
-v 显示同步过程的信息
-t 保留文件的时间标记
-o 保留文件的属主标记
-p 保留了文件的权限标记
-D 保留了设备文件和一些特殊的文件
-S 对零散文件的处理
-g 保留了文件的属组信息
但这些都太烦了,rsync考虑到这一点,提供了-a选项.它相当于-rlptgoD,几乎是一锅端的概念.考虑到大文件和网络问题再加上-z压缩.考虑到码农的强迫症,有像我一样喜欢欣赏cpu努力干活的时候刷出来一屏一屏的数据的,加上-v.如果还嫌不够细致,就加上--progress.如果嫌麻烦,就改成-P,外送一个--partial.所以对我来说,传文件的标配是 -avzP. 另外,rsync有一些其它的选项需要了解:
--deamon 后台模式,这就是起rsync服务的命令.牛x吧,这一个程序又可以起服务端又可以当客户端用.我还是第一次见到.deamon模式下有一些它所特有的参数
--include/exclclude/filter 过滤规则,rsync特有的文件提取和过滤,后面会讲到
-e --rsh=COMMAND specify the remote shell
-b, --backup make backups (see --suffix & --backup-dir)
-n, --dry-run show what would have been transferred.这个相当于是在你定义好过滤规则后,没有把握是不是完全正确,使用这个命令rsync会把将要传送的文件名列出来但不执行拷贝动作,相当于直接把过滤规则解释出来给你看.当然你不定义过滤规则就是你要求的所有文件了
基本上,了解上面这些选项,客户端的功能大多都够用了.
阶段2.rsync服务端配置.
上面已经说过了,rsync是一个C/S杂交体,它就一个程序即可以当客户端也可以当服务端用.--daemon一秒钟变身服务端. /etc/services文件里记录了rsync默认使用873号端口.当然像别的服务一样,rsync同样是需要配置文件的.rsync默认是找/etc/rsyncd.conf.有两点比较奇怪,一是居然用的rsyncd这个名字,二是默认/etc目录下没有这个文件.当然我们新建一个就好了.具体的格式大家可以man一下rysncd.conf,里面有详细的介绍.其实就跟samba这种比较类似,下面是一个简单的rsyncd.conf:
#指定访问组
gid = nobody
#禁止chroot(不可连接后切换用户)
use chroot = no
#允许访问目录列表
list = yes
#最大的连接数为10
max connections = 10
#存放进程标识文件的路径
pid file = /var/run/rsyncd.pid
#存放日志文件的路径
log file = /var/log/rsyncd.log
#允许访问rsync 服务的地址范围
hosts allow = 10.81.0.0/16
#此为开放的tag:
[data]
path = /home/work
#注释信息,有印象吗,这个信息出现在 rsync rsync://xxxxxx的浏览输出中
comment = It's my fucking data!
#标识为可读
read only = yes
#授权的用户名
auth users = work
#授权用户的密码文件位置
secrets file = /etc/rsyncd.pass
[etc]
path = /etc
#注释信息
comment = It's etc
开头定义全局参数,在每个tag里可以自己定义自己的玩法.全局的参数大多比较好理解,不好理解的一般也用不上.在man rsyncd.conf里有详细的介绍.tag里必须要有的是path,指定了你能aceess的目录.注意user的权限问题.然后一个重要的就是secrets file.通过它可以实现scp让人一直很难避免的手动输入密码问题.
对于这个配置文件,我要强调一下.注释不要写在一行的后面,一定要用#顶行写.因为我做过测试,在1.62这个版本上,注释和配置写在一行会导致rsync服务出错.可恶的是它居然不报错,就是连不上,而且出错信息尽是auth failed这种,让你以为自己密码填错了.连日志都没有,查起来非常麻烦.而且最好用英文写注释.码农的世界不欢迎acsill码外的符号.
rsync支持--config-file选项,指定配置文件(值得注意的一点是,这个老版本的ms找不到配置文件,rsync会无声无息的退出,一句话都不打出来,给人一种它在后台服务的假象.新的版本解决了这个问题).其它还有杂七杂八的选项关于配置这块的.
对于rsync这种服务,可以用命令行起独立模式,但一般都交给xinetd托管.只需要修改/etc/xinetd.d/rsync里的disable,改成no,然后重启xinetd服务,即:
sed -i '/disable/s/=.*$/= no/' /etc/xineted.d/rsync && /etc/init.d/xinetd restart
使用chkconfig --list 和netstat -tnpl|grep xinetd查看,一个on一个监听873端口,说明rsync服务已准备好.
[root@10.81.47.94~]# chkconfig --list rsync
rsync on
[root@10.81.47.94~]# netstat -tnpl|grep xinetd
tcp 0 0 0.0.0.0:873 0.0.0.0:* LISTEN 2473/xinetd
此时,在客户端可以用后两种网络模式连了.如
[work@10.81.52.135]~/haha>$ rsync -avzP 10.81.47.94::data/ss ./
Password:
receiving file list ...
15 files to consider
ss/
ss/aa -> /home/work/
ss/bigfile
838860800 100% 68.24MB/s 0:00:11 (1, 20.0% of 15)
ss/ff
21 100% 0.03kB/s 0:00:00 (2, 26.7% of 15)
ss/file0
1048576 100% 1.60MB/s 0:00:00 (3, 33.3% of 15)
ss/file1
1048576 100% 1.59MB/s 0:00:00 (4, 40.0% of 15)
ss/file2
1048576 100% 1.49MB/s 0:00:00 (5, 46.7% of 15)
ss/file3
1048576 100% 1.48MB/s 0:00:00 (6, 53.3% of 15)
ss/file4
1048576 100% 1.46MB/s 0:00:00 (7, 60.0% of 15)
ss/file5
1048576 100% 1.45MB/s 0:00:00 (8, 66.7% of 15)
ss/file6
1048576 100% 1.39MB/s 0:00:00 (9, 73.3% of 15)
ss/file7
1048576 100% 1.38MB/s 0:00:00 (10, 80.0% of 15)
ss/file8
1048576 100% 1.36MB/s 0:00:00 (11, 86.7% of 15)
ss/file9
1048576 100% 1.35MB/s 0:00:00 (12, 93.3% of 15)
ss/gcc.inf
1245769 100% 1.50MB/s 0:00:00 (13, 100.0% of 15)
sent 367 bytes received 1141032 bytes 69175.70 bytes/sec
total size is 850592361 speedup is 745.22
当然也可以使用第三种模式查看:
[work@10.81.47.94]~/ss>$ rsync rsync://10.81.47.94/data/ss/
Password:
drwxrwxr-x 4096 2012/04/08 05:43:34 .
lrwxrwxr-x 11 2012/04/08 04:39:59 aa
-rw-rw-r-- 838860800 2012/04/08 05:43:34 bigfile
-rw-rw-r-- 21 2012/04/08 04:35:37 ff
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file0
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file1
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file2
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file3
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file4
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file5
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file6
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file7
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file8
-rw-rw-r-- 1048576 2012/04/08 04:37:12 file9
-rw-rw-r-- 1245769 2012/04/08 05:41:48 gcc.inf
到现在,rsync在我们看来只是一个cp和scp的集合体而已.但后面讲到的rsync的功能,应该是很多同志们很想要的.
配置secrets file可以实现无密码拷贝.这比用expect包装scp或者ssh相互配置信任或者用python的pxssh之流要爽多了.当然两台ssh相互信任的主机通过第一种网络模式也是可以无密码拷贝的.
secrets file就是上面提到的conf里配置的密码文件,一般放在etc目录下,纯文本.这个文件有两点要注意:一是权限设成600,二是格式为"user:password",仅此一行.最好不要多空格少空格的,以免夜长梦多.user是与该secrets file同tag下定义的user名称相同,password自己随便写.比如work:abcd.同时,在客户端上配置一个同样的文件,文件名随意(例如pss),位置随意,同样两点要求:一是权限设成600,二是只写入password,不要user:,即服务端定义的abcd.处理完这些后,在客户端使用 --password-file=pss,就可以无密码拷贝了.我觉得这个比较好的一点是密码自己定义,变算暴露了也不会影响work的登陆密码.rsync有自己的一套权限管理.
阶段3 使用过滤功能.rsync有着自己定义的一套过滤语法,很强大但是语法很怪异,秉承了unix家庭一贯的传统.而且由于我这里的rsync版本很老,只有1.6.2,新的现在已经3.0.9了.我只好做了个虚拟机装了个新的os.这样就没办法做网络测试了,但本地的逻辑是一样.来看看:
[QThread@Heineken ss]$ tree ../aa
../aa
|-- 1.a
|-- 1.b
|-- 1.c
`-- dir
|-- 2.a
|-- 2.c
`-- dir2
|-- 3.a
|-- 3.b
`-- 3.c
2 directories, 8 files
把目录aa下的所有.a文件拷贝到当前目录下(所有都是保留目录的):
[QThread@Heineken ss]$ rm -rf * && rsync -avz --filter='+ */' --filter='+ *.a' --filter='- *' ../aa/ ./ && tree .
sending incremental file list
./
1.a
dir/
dir/2.a
dir/dir2/
dir/dir2/3.a
sent 3186 bytes received 80 bytes 6532.00 bytes/sec
total size is 14660 speedup is 4.49
.
|-- 1.a
`-- dir
|-- 2.a
`-- dir2
`-- 3.a
还有另一种方法:
[QThread@Heineken ss]$ rm -rf * && rsync -avz --filter='+ */' --filter='-! *.a' ../aa/ ./ && tree .
sending incremental file list
./
1.a
dir/
dir/2.a
dir/dir2/
dir/dir2/3.a
sent 3186 bytes received 80 bytes 6532.00 bytes/sec
total size is 14660 speedup is 4.49
.
|-- 1.a
`-- dir
|-- 2.a
`-- dir2
`-- 3.a
2 directories, 3 files
稍微解释一下,其实我也只是一知半解.filter是定义过滤条件,一个过滤条件分两个部分:rule和patten,两个通过空格或者下划线相连.我这里都用的是空格.3.0.9版本一共支持以下几种rule:
exclude, - specifies an exclude pattern.
include, + specifies an include pattern.
merge, . specifies a merge-file to read for more rules.
dir-merge, : specifies a per-directory merge-file.
hide, H specifies a pattern for hiding files from the transfer.
show, S files that match the pattern are not hidden.
protect, P specifies a pattern for protecting files from deletion.
risk, R files that match the pattern are not protected.
clear, ! clears the current include/exclude list (takes no arg)
实话说,本人英文水平实在有限,大部分没看懂.只会用前两个.前两个的意思就是一个是包含,一个是剔除.如果没有匹配的,就默认包含,这就是为什么每个后面都要有个exclude的filter的意思.因为第一个filter已经定义是包含了所有目录,所以如果不剔除的话就相当于啥都拷贝了.大家可以试一试.
对于patten,这是个非常奇怪的逻辑,本人英文水平实在有限,绝大部分没看懂.有各种匹配,各种符号,*/,**/,**都是不同的意思.下面给出man rsync里的几个例子,结合例子看应该还是能懂一点的:
- "- *.o" would exclude all names matching *.o
- "- /foo" would exclude a file (or directory) named foo in the transfer-root directory
- "- foo/" would exclude any directory named foo
- "- /foo/*/bar" would exclude any file named bar which is at two levels below a directory named foo in the transfer-root directory
- "- /foo/**/bar" would exclude any file named bar two or more levels below a directory named foo in the transfer-root directory
- The combination of "+ */", "+ *.c", and "- *" would include all directories and C source files but nothing else (see also the --prune-empty-dirsoption)
- The combination of "+ foo/", "+ foo/bar.c", and "- *" would include only the foo directory and foo/bar.c (the foo directory must be explicitly included or it would be excluded by the "*")
对于第一个例子,我们要提取所有*.a的文件,第一个条件一般都需要,就是包含所有当前目录和其子目录.第二个条件就是包含我们要过滤的.a文件,第三个条件是剔除所有其它的文件.这个时候大家可能会问到,为什么这么麻烦,有了第二个为什么还要第一个.好,我们来看看:
[QThread@Heineken ss]$ rm -rf * && rsync -avz --filter='+ *.a' --filter='- *' ../aa/ ./ && tree .
sending incremental file list
./
1.a
sent 2918 bytes received 34 bytes 5904.00 bytes/sec
total size is 14540 speedup is 4.93
.
`-- 1.a
0 directories, 1 file
看到没有,如果没有第一个条件,子目录下的.a就全部被忽略了.这还不如不用filter直接../aa/*.a来的实在.
对于第二个例子,同样是提取所有*.a,我们在最后一个-filter里做文章,加了一个!,就是否的意思.意思是包含所有文件,剔掉所有不是*.a的文件.一样达到了效果
那么对于第三个例子就简单了,提取所有的*.a和*.b文件.当然我们举一反三,如果有需求剔掉所有.b文件呢,应该这么写:
rsync -avz --filter='+ */' --filter='- *.c' ../aa/ ./
如果有需求,不要文件,只取出所有的目录结构呢,可以这样:
[QThread@Heineken ss]$ rm -rf * && rsync -avz --filter='+ */' --filter='- *' ../aa/ ./ && tree .sending incremental file list
./
dir/
dir/dir2/
sent 93 bytes received 23 bytes 232.00 bytes/sec
total size is 0 speedup is 0.00
.
`-- dir
`-- dir2
2 directories, 0 files
如果有需求,不要目录,取出来的所有*.a都放在当前目录下呢,我诚恳的告诉大家,我研究了半天也不知道怎么弄.但我直觉告诉我一定可以,只是本人资质有限罢了.
反正就是这个意思了,能不能领悟就看同志们的造化了.当然这些功能通过find+tar的命令在本地同样可以做到,例如:
cd ../aa && find . -name '*.a'|xargs tar cvf -|(cd ../ss && tar xvf -)
但是,find+tar可以从远程过滤文件拷贝回本地吗?scp可以做到.但scp只能使用原始的通配符,scp我印象中好像无法有很强的过滤文件的功能.对于rsync来说,这一切都不是它一行命令解决的问题.rsync的强大功能,我今天讲到的只能说是冰山的一角,今天只能说是简单的给大家介绍了一下rsync,如果有什么没讲清楚的地方,其实我也不一定清楚...