源路径带不带尾斜杠决定目录层级;rsync 默认只比 mtime 和大小,漏改要换 -c;断点续传靠 –partial。三大坑均经 WSL2 实测。
一、尾斜杠决定目录层级:先记两条等价写法
rsync -a /data/src /backup/ # 结果是 /backup/src/...,多一层 src
rsync -a /data/src/ /backup/ # 结果是 /backup/...,只拷内容
rsync -a /data/src/ /backup/src # 与上一条落点完全相同(实测等价)
实测同一份 src(含两个子目录):不带斜杠时目标树是 d1/src/a.txt;带斜杠时是 d2/a.txt,目录本身没有被搬过去。手册的说法:把源路径的尾 / 理解为”拷这个目录的内容”,不带就是”把这个目录拷过去”;并给出与实测一致的等价对 rsync -av /src/foo /dest 与 rsync -av /src/foo/ /dest/foo [1]。配套规律:目标路径带不带斜杠不影响结果(实测 d2 与 d2/ 落点相同);只有源路径的斜杠改变层级。首次创建目标目录时 rsync 会自己建(实测 created directory 提示)。
二、–delete 的安全预览:先 -ain,再动手
rsync -ain --delete /data/src/ /backup/ # 预览:只打印,不落盘
rsync -ai --delete /data/src/ /backup/ # 确认无误后再去掉 n 实跑
手册对 –dry-run 的原话:做一次不落盘的试跑,常与 -v、-i 组合,用来在真跑之前看清 rsync 将要做什么;并且承诺 -i 的逐行输出在试跑与实跑之间应当完全一致 [1]。实测印证:预览里 *deleting sub2/old.log,实跑删除的正是同一行。–delete 家族还有 –delete-before / –delete-during / –delete-delay / –delete-after 四个时机变体,Debian 手册明确 rsync 3.0.0 起 –delete 默认就是 –delete-during [2]。两个实测护栏:–max-delete=2 时删到第 2 个就停,报 Deletions stopped due to --max-delete limit、错误码 25;预览里的删除行以 *deleting 开头,扫一眼这一列就能预判会被删什么。
三、排除规则:–exclude 与 –filter 的锚点差别
rsync -a --exclude='*.log' /data/src/ /backup/ # 任意层级的 .log 都排除
rsync -a --filter='-p /sub2/' /data/src/ /backup/ # 只排除顶层 sub2/(实测)
rsync -a --exclude-from=/etc/rsync.ignore /data/src/ /backup/ # 规则写文件里
手册的 FILTER RULES:模式前加锚 / 就锚定到 transfer 起点而不是末端,例如 /foo/** 只匹配 transfer 根下的 foo [1]。实测 --filter='-p /sub2/' 后目标里 sub1 正常同步、sub2 整个消失,而上一节不带锚的写法会把各层同名目录一起排掉。-p 表示该规则同时作用于推送方向 [2]。规则多时用 –exclude-from 指一个规则文件,便于版本管理与复用。
四、rsync 凭什么判断”文件没变”:默认 mtime+大小
rsync 的默认比对是 mtime 加文件大小,不是内容。实测构造了一个”内容已改、大小相同、mtime 被 touch 成一样”的文件:默认 rsync -ai 一行输出都没有(判定无需传输);换成 rsync -aic 立刻传输,itemize 行写作 >fc........,c 标记传输方式已换成校验和 [1]。所以从备份介质恢复、解压保留原时间戳的归档之后,补一次 -c 才可靠。手册还给出 –modify-window=NUM(-@):两个时间戳差值不超过 NUM 即视为相等,默认 0;推荐对 FAT/exFAT 设 1,因为 FAT 的时间只有 2 秒分辨率 [2]。本地对拷时 rsync 默认走 whole-file(-W)而不算增量,手册明确”源与目标都是本地路径时默认如此” [1],跨机器才轮到 delta 算法加 -z 压缩(文档口径,未实测)。
五、大文件断了怎么续传:–partial 实测对比
rsync -a --partial --bwlimit=2000 /data/big.bin /backup/ # 中断后保留半截文件
rsync -a --partial-dir=.rsync-partial /data/big.bin /backup/ # 半截放临时目录
实测 120MB 文件限速传输、3 秒后 SIGTERM 杀掉:默认行为下退出码 20(手册退出码表:20 = 收到中断信号 [1]),目标目录里半截文件被删、重跑从 0 开始;加 –partial 后 6193152 字节的半截留在原地,重跑 itemize 显示 >f.st......——只补差异段后完成。手册对 –partial 的解释:告诉 rsync 保留部分传输的文件,让后续传输快得多;–partial-dir 则把半截文件放进指定目录、续传用完自动删除,且与 –partial、–delay-updates 互斥 [2]。注意 –partial-dir 的官方提醒:本地拷贝默认 whole-file 时,找到的 partial-dir 文件会被直接移除(文档口径);实测续传确实以完整传输收尾。限速用 –bwlimit,单位 KB/s(手册口径),cron 白天的备份任务建议配上,避免抢生产带宽。
六、出错怎么读:退出码与排错速查
rsync 失败时先看退出码再翻日志。手册的 EXIT VALUES 表:0 成功、1 语法或用法错误、23 部分源/目标缺失、24 部分传输文件消失、25 被 –max-delete 拦停、10/11/12 套接字/文件/协议流 I/O 错误、20 收到中断信号 [1]。实测:源目录不存在退出码 23;未知选项退出码 1;SIGTERM 中断退出码 20;–max-delete 拦停报错误码 25。
| 现象 | 原因 | 处理 | | — | — | — | | 目标里多出一层同名目录 | 源路径没带尾斜杠 | 源加 / 或目标补上目录名(实测) | | 文件明明变了却没同步 | mtime 与大小都没变 | 补一次 -c 校验和比对(实测) | | 半截文件消失、白传了 | 默认中断即删 | 加 –partial 或 –partial-dir(实测) | | 目标文件属主变成执行用户 | 非 root 无权 chown | 用 root 跑,或 –chown 映射(实测) | | –delete 不敢下手 | 怕误删 | 先 -ain 预览,再配 –max-delete(实测) | | 大目录首扫慢、内存高 | 递归扫描全量建列表 | 试 –no-inc-recursive 对比(文档口径) |
**常见提问**
/src/foo → /dest 与 /src/foo/ → /dest/foo 结果相同 [1]。局限性:全部实测在 WSL2 的 Ubuntu 24.04(rsync 3.2.7)完成;远程 SSH 传输、–partial-dir 在 delta 模式下的续传效果、-z 与 –whole-file 的跨机性能差异、–no-inc-recursive 的大目录表现均为文档口径,未在本机复现;RPM 系发行版未测。
**实测记录**
d1/src/...,带斜杠落 d2/...;目标带不带斜杠结果相同。*deleting sub2/old.log 与实跑逐行一致;–max-delete=2 删 2 停 1,报错误码 25。>fc........。>f.st...... 完成;–partial-dir 半截进 .rsync-partial,本地 whole-file 默认下续传为完整传输。参考资料
- [1] rsync(1) – Linux manual page (man7.org)(rsync(1) 手册)
- [2] rsync(1) — Debian bookworm 手册页(Debian rsync(1))
文中主要命令已在 WSL Ubuntu(24.04)实测并核对其在 Debian 系与通用发行版的文档口径。