rsync --exclude 基于源目录相对路径匹配,不加尾斜杠时排除路径以根目录为基准,加尾斜杠则以源目录内容为基准;需用单引号防止 shell 展开,复杂规则建议用 --exclude-from 文件。

rsync --exclude 参数必须写对路径相对关系
rsync 的 --exclude 规则不是按绝对路径匹配,而是基于 SOURCE 目录的相对路径。比如你执行 rsync -av /home/user/project/ /backup/,那么 --exclude="logs" 实际匹配的是 project/logs,而不是系统根目录下的 /logs。
常见错误是写成 --exclude="/project/logs" 或 --exclude="/logs",这会导致规则完全失效——rsync 根本不认。
- 正确写法:
--exclude="logs"(排除 project/logs) - 若要排除 project/src/utils 下的所有 .tmp 文件:
--exclude="src/utils/*.tmp" - 路径中不要加前导
/,除非你用的是--exclude-from且文件里明确写了相对路径 - 多个排除项可重复使用
--exclude,顺序无关
同步目录末尾斜杠影响 --exclude 是否生效
这个细节极容易被忽略:源路径结尾是否带 /,直接决定 --exclude 的作用对象层级。
例如,想排除 config 目录:
-
rsync -av /app/ /backup/ --exclude="config"→ 排除的是/app/config(正确) -
rsync -av /app /backup/ --exclude="config"→ 排除的是/config(即根目录下叫 config 的目录,不是 /app/config)
根本原因是:不带 / 的 /app 被视为“把 app 这个目录整体复制过去”,rsync 内部会把排除路径相对于 / 解析;而 /app/ 表示“复制 app 目录里的内容”,排除路径才相对于 app/ 解析。
建议统一用带尾部 / 的写法,更符合直觉,也和大多数文档示例一致。
排除嵌套子目录或通配符需注意 shell 展开
如果你在命令行里写了 --exclude="*.log" 却发现没生效,大概率是 shell 提前把 *.log 当作当前目录下的文件展开了,传给 rsync 的已经不是通配符字符串,而是空值或具体文件名。
- 务必用单引号包裹模式:
--exclude='*.log',防止 shell 解释 - 双引号在某些环境下也可能触发变量展开(如
$HOME),不推荐 - 想排除所有以
.git开头的目录:--exclude='.git*'或更精准的--exclude='.git'(因为 .git 是固定名) - 排除多级嵌套中的某类文件,比如
node_modules/**/test.js,rsync 本身不支持**,得靠--filter或多次--exclude
复杂排除逻辑建议用 --exclude-from 而非堆砌 --exclude
当要排除的条目超过 3 个,或者包含空格、特殊字符、需要注释说明时,硬编码一堆 --exclude 不仅难读,还极易出错。
创建一个排除规则文件,比如 rsync-exclude.txt:
logs/ temp/ *.swp .DS_Store config/local.env
然后调用:rsync -av --exclude-from='rsync-exclude.txt' /source/ /dest/
注意:--exclude-from 文件里的每一行都是独立规则,同样遵循相对路径规则,且自动忽略空行和 # 开头的注释行。比命令行拼接健壮得多。
真正麻烦的从来不是写一条排除规则,而是搞清路径基准、shell 干预、斜杠语义这三者的叠加效应。每次不确定时,先加 --dry-run 看它到底打算同步哪些文件,比猜强十倍。











