rysnc命令过滤规则入门教程
投稿:mdxy-dxy
0、前言
rsync 命令的过滤规则功能非常强大,但网上几乎没有详解此主题的资料,让人学习和理解有一定的难度。官网文档 和man rsync
手册是英文的,没有什么示例说明,不好理解。即使有人翻译了手册,理解起来也是有一定的难度。
故而有了此教程,结合实际命令对过滤规则的相关概念、逻辑和使用技巧做一个比较透彻的讲解。希望有兴趣学习的朋友,可以快速的入门,节省时间。为什么说是入门呢?因为 rsync 的过滤规则相关内容里,还包含了一些高级技巧,个人感觉实际项目中用到的机会比较少,并未包含在此教程里。
本教程主要分为以下三部分:
- 1.概述:讲解 rsync 过滤规则的相关概念和内部运行逻辑
- 2.操作和修饰符:讲解过滤规则中的操作和修饰符
- 3.匹配模式:讲解过滤规则中的匹配模式
- 4.使用场景举例:使用具体命令举例讲解过滤规则的使用技巧
1、概述
1.1 什么是 rsync 的过滤规则?
rsync 过滤规则是用于定义哪些文件要传输(包含某些文件)哪些文件不要传输(排除某些文件)的一些规则。这些规则可以直接写在命令参数里,也可以写在规则文件里,然后由命令引用。例如:
# 命令1.1-1:规则直接写在命令参数里 # --include="*.php" --exclude="*" 这两个参数配置了两条过滤规则 # 此命令将会只同步src_dir目录下的php文件(不包含子目录的) rsync -av --include="*.php" --exclude="*" src_dir/ dst_dir/ # 命令1.1-2:通过规则文件配置规则 # rsync.rules 为规则文件,可以使用相对路径或绝对路径 rsync -av -f ". ./rsync.rules" src_dir/ dst_dir/ rsync -av -f ". /www/rsync.rules" src_dir/ dst_dir/
rsync.rules 规则文件的内容如下(具体语法后文说明):
# 只同步php文件 + *.php - *
1.2 配置过滤规则的方式有哪些?
与过滤规则有关的选项包括主要有:
- --include=PATTERN :设定一条包含规则,如:
--include="*.php"
- --exclude=PATTERN :设定一条排除规则,如:
--exclude="*"
- --include-from=FILE :指定一个文件,文件中一行一条包含规则,以
;
或#
开头的行为注释,空行被忽略 - --exclude-from=FILE :指定一个文件,文件中一行一条排除规则,以
;
或#
开头的行为注释,空行被忽略 - --filter=RULE, -f :设定一条过滤规则,可能是排除或包含规则(如:
-f "- *.php"
),也可能其它类型的规则(如包含一个规则文件-f ". ./rsync.rules"
)
这些选项配置的规则,其本质是一样,只是描述方式有些差异。其中 --filter=RULE, -f
选项支持完整的规则表达语法,其它的选项都可以转化为此选项的表达。举例如下:
# 以下的都是命令是完全等价的,-f 方式更简单,后文将会更多的选用 -f 的方式表达 # --include="xxx" 等价于 -f "+ xxx" # --exclude="xxx" 等价于 -f "- xxx" rsync -av --include="*.php" --exclude="*" src_dir/ dst_dir/ rsync -av -filter "+ *.php" -filter "- *" src_dir/ dst_dir/ rsync -av -f "+ *.php" -f "- *" src_dir/ dst_dir/
由 --include-from 或 --exclude-from 选项引入的规则文件,相当于每个规则前面自动加了 +
或-
。其规则文件类内举例如下:
# --include-from 或 --exclude-from 引用的规则文件,开头没有 + 或 - *.php *
1.3 过滤规则的工作方式
所有的过滤规则配置最终在 rsync 内部会形成一个有序的规则列表,在命令行中靠前选项,其规则的排序也靠前。随着要传输的(文件/目录路径)列表的构建,针对每个路径,rsync 会依次读取有序规则列表中的规则进行检查。当第一个规则匹配成功后,立即进行操作(包含或排除),并停止后面规则的检查;若所有规则都不不匹配,此路径默认为包含。若有递归选项时(如-r
-a
),如果子目录被规则排除,那么 rsync 不会递归检查此目录的内容了,也就是此目录下的文件和目录不会进行规则过滤也不会传输,相当于整个子目录都排除了。简单总结如下:
- 规则有顺序,同命令中参数配置顺序(从左到右)
- 扫描文件系统,读取(目录或文件的)路径后马上进行规则检查,确定包含还是排除
- 规则检查按序进行,若有命中立即包含或排除,并停止后续规则检查;若无规则命中,默认为包含
- 目录被排除时,其下所有子目录和文件都被排除
举例如下:
# 此命令会同步src_dir目录下的所有php文件(不包含子目录的) # 因为src_dir目录下每个文件和目录路径都会先由 -f "+ *.php" 规则检查,php文件符合此规则就被包含了,后面的 -f "- *" 规则不会检查了 # 其余类型的文件和子目录,不符合第一个规则,继续检查第二个规则时,都被排除了 # 子目录被排除后,其中即使有php文件,也不会被检查,所以此命令不会同步src_dir目录下子目录中的php文件 rsync -av -f "+ *.php" -f "- *" src_dir/ dst_dir/ # 调换两个参数的顺序,则完全不一样了 # 此命令将不会同步任何文件和目录 # 因为第一条规则把所有文件和目录到排除了,第二条规则没有机会生效 rsync -av -f "- *" -f "+ *.php" src_dir/ dst_dir/ # 此命令会同步src_dir目录下的所有php文件(包含子目录的) # 规则 -f "+ */" 会匹配并包含所有子目录路径,所以 rsync 会检查所有的子目录,然后其中的php文件被包含了 rsync -av -f "+ *.php" -f "+ */" -f "- *" src_dir/ dst_dir/
1.4 配置过滤规则的语法
过滤规则的语法如下:
操作 [匹配模式] 操作,修饰符 [匹配模式]
操作:是诸如+
(包含)和-
(排除)。还有之前引用规则文件(-f ". ./rsync.rules"
)的.
号,其意义是包含规则文件的操作。还有其它的一些后文详细说明。
修饰符:可用于改变规则的一些行为方式,后文详细说明。
匹配模式:用于匹配字符串的模式,类似正则表达式,可用于检查字符串是否符合某种模式。若符合就说是匹配的,或说命中了。中括号表示匹配模式是可选的,因为某些特殊的操作,没有匹配模式。
操作和匹配模式之间的空格必须是一个英文空格,也可以使用_
字符代替,这在命令行中直接写规则时,可以省略引号。例如:
# 以下两条命令完全等价 # 省略引号的写法应注意其中的*号被意外扩展为路径了 # 建议使用空格加引号的写法,更清晰和安全 rsync -av -f "+ *.php" -f "+ */" -f "- *" src_dir/ dst_dir/ rsync -av -f +_*.php -f +_*/ -f -_* src_dir/ dst_dir/
1.5 测试方法
若需要反复修改命令进行测试,按照实际同步的方式,可能需要不断的删除目标目录的文件,这多少有点不方便。有一个解决办法就是,稍微改变一下 rsync 命令,去掉目标目录不写,则表示不实际同步数据,只列出需要同步的文件/目录列表。例如:
# 原命令 rsync -av -f "+ *.php" -f "+ */" -f "- *" src_dir/ dst_dir/ # 修改后 # 此命令并不会实际同步数据,只会输出要同步的文件/目录列表 rsync -av -f "+ *.php" -f "+ */" -f "- *" src_dir/
2、操作和修饰符
2.1操作
规则类型是由操作决定的,操作不同可以看作是规则类型不同。操作一共有以下9种,每种操作都有对应的标识,分为长标识和短标识,一般配置时都是使用短标识
| 序号 | 长标识 | 短标识 | 操作说明 | 说明 | | ---- | --------- | ------ | ------------------------------ | ---------------------- | | 1 | exclude | - | 排除操作 | 排除符合匹配模式的路径 | | 2 | include | + | 包含操作 | 包含符合匹配模式的路径 | | 3 | merge | . | 引入规则文件 | 参考:命令1.1-2 | | 4 | dir-merge | : | 指定每个目录里要合并的规则文件 | 针对传输目录,不常用 | | 5 | hide | H | 指定从传输中隐藏文件的模式 | | | 6 | show | S | 指定某些文件不会被隐藏 | | | 7 | protect | P | 指定某些文件受保护不被删除 | | | 8 | risk | R | 指定某些文件不受保护 | | | 9 | clear | ! | 清除当前包含/排除列表 | 无匹配模式 |
最基本也是最常用的操作就是前3个,比较好理解,之前的示例里已经有说明,这里不再重复。
2.2 修饰符
修饰符只可用于包含/排除操作(+/-),一共有以下7种。当操作使用短标识是,中间的逗号是可以省略的。
1.修饰符/
包含/排除操作后面的匹配模式,本来是针对传输目录的相对路径进行匹配。加了此修饰符后,会把相对路径转换为绝对路径后进行匹配,匹配的方式和规则保持不变。例如:
# 假设 src_dir 的绝对路径未为:/www/src_dir # 命令2.2-1:此命令将同步src_dir下的所有php文件,但不包括admin.php # 当扫描到admin.php文件时,其相对路径是 'admin.php'。转化为绝对路径为 '/www/src_dir/admin.php' # 使用 '-f "-/ src_dir/admin.php"' 规则检查时,匹配(为什么匹配请看后文匹配模式),然后排除。 rsync -av -f "-/ src_dir/admin.php" -f "+ *.php" -f "- *" src_dir/ # 同理此命令效果相同 rsync -av -f "-/ /www/src_dir/admin.php" -f "+ *.php" -f "- *" src_dir/
2.修饰符!
表示否定,对匹配结果进行取反,把匹配成功当做匹配失败,把匹配失败当做匹配成功。例如:
# 此命令只同步src_dir下的php文件 # 扫描src_dir目录下的文件和目录时,php文件以外的目录和文件都匹配失败,取反变成匹配成功,排除 # 而php文件最终变成匹配失败,算未命中任何规则,默认保留 rsync -av -f "-! *.php" src_dir/ # 经测试,/和!两个修饰符可以同时使用 # 修改命令2.2-1 # 此命令将只同步admin.php文件 rsync -av -f "-/! src_dir/admin.php" -f "+ *.php" -f "- *" src_dir/ # 但以下命令报错了 rsync -av -f "-!/ src_dir/admin.php" -f "+ *.php" -f "- *" src_dir/ # 但改为单引号后正常了,可能是双引号中的某些字符被意外解析了 # 也就是多个修饰符时,顺序不影响 # 这又是一条经验,如非必要,参数请用单引号 rsync -av -f '-!/ src_dir/admin.php' -f "+ *.php" -f "- *" src_dir/
3.修饰符C
未仔细研究,略过
4.修饰符s
未仔细研究,略过
5.修饰符r
未仔细研究,略过
6.修饰符p
未仔细研究,略过
7.修饰符x
未仔细研究,略过
3、匹配模式
包含和排除规则,都有一个匹配模式,如 过滤规则- *.php
中的字符串*.php
就是此规则的匹配模式。用于检查匹配传输路径(要同步的原目录中文件或目录的相对路径,有修饰符/
时为绝对路径)。匹配模式就是描述路径特征的一个字符串,如 *.php
描述的就是路径末尾的名称()必须是.php
结尾。功能和用法类似正则表达式,但比正则表达式简单。
传输路径:是指 src_dir 中文件或目录的相对路径,格式类似如下:
server.php services.php session.php view.php config/ config/services.php config/session.php config/view.php routes/ routes/api.php routes/channels.php routes/console.php routes/web.php
匹配模式将是和这些路径进行匹配。
关于匹配模式,我一共总结了10条模式规则:
- 模式以
/
开头时,表示模式必须匹配路径的开始;否则可以匹配路径中任意一层名称。如:/*.php
- 模式以
/
结尾时,表示模式只匹配目录,否则可以匹配目录或文件。如:config/
- 模式中间的
/
表示路径分隔符。如:subdir/view.php
*
匹配任意长度的任意字符,但不匹配/
。如:*.php
**
结尾时匹配任意长度的任意字符(包括/
)。如:app/**
匹配路径"app/xx/xx/a.txt"
***
结尾时匹配任意长度的任意字符(包括/
),还包括目录本身。如:app/***
匹配路径"app"和"xxx/app"
?
匹配/
以外的任意一个字符[]
匹配一个某一类字符,如:[a-z]
匹配一个小写字母,[0-9]
匹配一个数字- 模式默认必须匹配到路径的末尾。如:
foo
匹配"foo"
和"xx/foo"
,但不匹配"xx/foo1"
和"foo/xx"
- 路径被匹配的部分必须是包含完整的(目录或文件)名称,不可从名称中间切开。如:
foo
不匹配"xxx/afoo"
,abc/foo
不匹配"subdir/aabc/foo"
以下举例说明各条规则的使用:
4、使用场景举例
4.1 场景:排除某些目录或文件不同步
此需求比较简单,因为默认包含所有路径,只需设定排除规则,排除对应的目录或文件即可
# 排除app和vendor目录不同步 # 注意此命令会排除名称是app或vendor的目录或文件,因为模式规则1 rsync -av -f '- app' -f '- vendor' src_dir/ # 此命令则只排除 src_dir 一级子目录中的 app 和 vendor rsync -av -f '- /app/' -f '- /vendor' src_dir/ # 排除更深层次的子目录 rsync -av -f '- /app/Admin' -f '- /vendor' src_dir/ # 排除隐藏文件/目录 和 php文件 # 因为模式规则9,10,4,模式`.*`相当于是要求路径最后的名称(文件或目录)必须是`.`开头 rsync -av -f '- .*' -f '- *.php' src_dir/
4.2 场景:只同步指定的子目录
因为传输路径若无规则命中默认是包含(同步),所以若要实现只同步指定目录,需主动写过滤规则排除不需要同步的路径。整体思路就是,先写规则包含要同步的路径,然后排除其余路径。先比较简单的只同步一级子目录开始
只同步一级子目录
以下所有命令均等价,只是实现思路不同。效果都是:只同步config目录(包括所有子目录和文件)
# 命令4.2-1:使用了模式规则1、4 # 因模式规则1,-f '- /*'规则排除了str_dir目录下出config外所有的文件和子目录 # 递归扫描config目录时,因不命中任何规则,所有子目录和文件都被默认包含 rsync -av -f '+ config' -f '- /*' src_dir/ # 命令4.2-2:使用了模式规则4、5、9 # -f '+ config'匹配config目录并包含 # -f '+ config/**' 匹配config目录下所有的子目录和文件的路径,包含。模式规则5 # 其余所有的路径被 -f '- *'匹配,排除。模式规则4、9 rsync -av -f '+ config/**' -f '+ config' -f '- *' src_dir/ #命令4.2-3: # -f '+ config/***' 匹配config目录以及其所有子目录和文件。规则6 rsync -av -f '+ config/***' -f '- *' src_dir/ #命令4.2-4: # 使用修饰符!取反,排除了config目录以及其所有子目录和文件路径以外的路径 # 相当于只同步config目录 rsync -av -f '-! config/***' src_dir/
扩展:只同步多个一级子目录
只同步config、app目录(包括所有子目录和文件)
# 注意两条命令的排除规则是不同的,可以参考体会一下模式规则1 rsync -av -f '+ config' -f '+ app' -f '- /*' src_dir/ rsync -av -f '+ config/***' -f '+ app/***' -f '- *' src_dir/
只同步更深层级的子目录
模仿只同步一级子目录的写法,可能会直接把命令写成rsync -av -f '+ app/Admin' -f '- /*' src_dir/
。但此命令并不能按预期工作。原因是rsync扫描到app路径时,并不能命中-f '+ app/Admin'
规则,然后就后面的规则排除掉了。然后就没然后了,此命令不会同步任何文件。
明白这个问题后,修正它,然后就可写出只同步app/Admin子目录(包含所有子目录和文件)的命令了,以下都是:
# 命令4.2-5: # 扫描到一级子目录app时,其路径并不会和规则 -f '+ app/Admin/' 匹配,因为模式规则9 # app 路径是有规则 -f '+ app' 命中包含的。此规则若去掉,则此命令不会同步任何文件和目录 # -f '- /*' -f '- /*/*' 两条规则是排除所有未被前面规则包含的一级子目录/文件和二级子目录/文件 # app/Admin/ 下的子目录/文件将不会在命中规则,默认包含 rsync -av -f '+ app/Admin/' -f '+ app' -f '- /*' -f '- /*/*' src_dir/ # 命令4.2-6:效果同命令3-5 # 思路同命令4.2-4 rsync -av -f '+ app' -f '-! app/Admin/***' -f '- /*' src_dir/ #命令4.2-6:效果同命令3-6,思路则不同 # -av -f '+ app'规则包含app # -av -f '+ app'规则包含app/Admin/目录及所有子目录和文件 # 其余路径由 -f "- *" 排除 rsync -av -f '+ app' -f '+ app/Admin/***' -f "- *" src_dir/ # 命令4.2-7 # -f '-! app/***'规则使用取反,只保留app子目录 # -f '+ app/Admin/' 包含app/Admin/目录,其余二级子目录由规则-f "- /*/*"排除 # app/Admin/目录下所有子目录和文件,无规则命中,保留 rsync -av -f '-! app/***' -f '+ app/Admin/' -f "- /*/*" src_dir/
扩展:只同步多个深层级的子目录
与只同步一个深层级子目录类似,也可以写出很多不同的命令。但问了减少出错,建议使用命令4.2-6的思路,比较简洁。给深层的子目录的所有父级目录都添加好包含规则,然后深层子目录添加***
的包含规则,最后是一条排除规则。
rsync -av -f '+ /app' -f '+ /app/Admin/***' -f '+ /vendor' -f '+ /vendor/psy' -f "- *" src_dir/
4.3 场景:快速复制目录结构
有时需要需要创建一个目录,其子目录层次结构与另一个目录结构一样,但不需要其中的文件,这可以用rsync命令快速完成
# 使用了修饰符!取反,排除了目录以外的路径。模式规则1 rsync -av -f '-! */' src_dir/ dst_dir/
5、总结
本文针对 rsync 过滤规则主要讲解了4大块内容:配置方法、内部运行方式、规则语法和使用技巧举例。其内容都是来自官方手册和实操测试,若有谬误,欢迎大家批评指正。也欢迎大家在评论区沟通交流 rsync 的各种经验和技巧。
另外还需强调的是,这个不是 rsync 过滤规则的全部内容,例如操作和修饰符的讲解并不完整,命令中的其它一些与过滤有关的选项(如:--prune-empty-dirs
)也未涉及。若有更高级功能的需求,请大家查阅官方手册。