使用 rsync 复制两个大型目录时,最稳妥的做法不是把两个源路径随手写进一条命令,而是先明确每个源目录对应哪个目标目录,再逐组执行:
|
|
每组任务都先用 --dry-run 预演,正式复制时保留未完成文件并记录日志,复制结束后再执行一次只读比对。
如果普通比对没有输出,说明 rsync 按文件大小、修改时间和相关属性没有发现差异;如果要确认文件内容也一致,再增加 --checksum 做全量读取校验。
可以直接采用的安全方案
下面假设源盘和目标盘都已正确挂载:
|
|
先创建目标目录:
|
|
分别预演两组同步:
|
|
确认源、目标路径和变更列表都正确后,去掉 -n,串行执行正式同步:
|
|
第一次迁移建议不要添加 --delete。
这样即使目标目录中有额外文件,rsync 也不会删除它们。等目录结构和校验结果都确认无误后,再决定是否需要把目标做成源的完全镜像。
为什么两个目录最好分两次运行
rsync 的最后一个位置参数是目标目录,前面的参数都被视为源。
下面这种写法:
|
|
表示把两个源都汇入同一个 /target/,并不表示 /source/a/ 对应 /target/a/、/source/b/ 对应 /target/b/。
当两个目录需要分别落到两个目标路径时,应执行两次 rsync,或者写一个明确的串行脚本。
分开运行还有几个实际好处:
- 每个目录有独立日志和退出状态;
- 某一组失败时,不会掩盖另一组的结果;
- 校验时可以逐组定位差异;
- 可以让机械硬盘顺序读写,避免两个任务争抢磁头;
- 能为不同目录设置不同的排除规则。
如果两个源确实要汇入同一个目标,先确认它们是否包含同名相对路径。
例如两个源都有 2026/report.pdf,后执行的源可能覆盖先执行的同名文件。此时更安全的做法是为它们保留独立子目录。
先确认挂载点,避免复制到系统盘
大目录迁移最危险的错误之一,是目标磁盘没有挂载成功,但目标路径仍然存在。
此时 rsync 会把数据写进根文件系统中的普通目录,直到系统盘被写满。
开始前检查块设备、文件系统和挂载点:
|
|
重点确认:
/mnt/disk1和/mnt/disk2对应预期设备;- 目标盘可用空间足够;
- 目标挂载不是只读状态;
- 两个路径不是意外指向同一个文件系统位置;
- 目标路径不是源路径内部的子目录。
可以用下面的命令查看解析后的真实路径:
|
|
再做一个小型写入测试:
|
|
这里只删除刚刚明确创建的测试文件,不要用通配符清理目标目录。
目录末尾斜杠决定复制层级
这两条命令的结果不同:
|
|
第一条复制 /source/ 里面的内容:
|
|
第二条复制 source 目录本身:
|
|
同步两个已经建立好的对应目录时,通常在源路径和目标路径后都写 /:
|
|
不要只凭目录名称猜测结果。第一次执行前用 --dry-run --itemize-changes 查看将创建的相对路径。
推荐参数分别解决什么问题
基础参数组合是:
|
|
其中:
| 参数 | 作用 | 注意事项 |
|---|---|---|
-a |
归档模式,递归并保留常见属性 | 不等于自动保留所有硬链接、ACL 和扩展属性 |
-H |
保留硬链接关系 | 大量硬链接会增加内存消耗 |
-A |
保留 POSIX ACL | 目标文件系统必须支持 ACL |
-X |
保留扩展属性 | 目标文件系统必须支持 xattr |
--numeric-ids |
直接保留 UID、GID 数值 | 适合 Linux 磁盘迁移和系统数据复制 |
--partial |
中断后保留未传完的文件 | 下次运行仍会检查并继续传输 |
--partial-dir=.rsync-partial |
把未完成文件放进专用目录 | 校验完成前不要手工删除该目录 |
--info=progress2 |
显示整个任务的总体进度 | 统计总量会随文件列表生成方式变化 |
--info=stats2 |
结束时显示传输统计 | 不能替代复制后的独立校验 |
--log-file |
把详细记录写入日志 | 日志目录必须可写 |
如果复制的是普通文档、照片和视频,而且源目录没有硬链接、ACL 或扩展属性,可以按实际需求减少参数。
不要机械地认为参数越多越安全。
例如目标是 FAT、exFAT 或某些网络文件系统时,权限、所有者、ACL、xattr 可能无法完整保存,-A、-X 或所有者设置可能报错。
先查看两端文件系统类型:
|
|
如果两端能力不同,应先明确需要保留的是文件内容,还是完整的 Linux 元数据。
增量同步到底会复制什么
默认情况下,rsync 主要根据文件大小和修改时间判断文件是否需要更新。
再次运行相同命令时:
- 新文件会被复制;
- 大小或修改时间变化的文件会被更新;
- 没有变化的文件会被跳过;
- 目标独有文件会保留;
- 中断的文件会按照当前状态重新检查并继续处理。
这就是增量同步适合大目录迁移的原因。
但它不是文件系统快照。
如果源目录在复制过程中持续变化,最后得到的目标可能包含不同时间点的文件状态。普通照片库或归档目录可以在首次复制后再运行一次增量补齐;数据库、虚拟机镜像和正在写入的应用数据应先停止服务、冻结写入或使用文件系统快照。
预演时怎样阅读变更列表
推荐的预演命令是:
|
|
-n 是 --dry-run 的短写,只计算计划,不写入文件。
--itemize-changes 会显示每个变化项及原因。常见输出形式包括:
|
|
大致可以这样理解:
>f+++++++++:目标中没有该文件,将新建;>f开头且后面有属性标记:文件内容或属性将更新;.d:目录本身的属性需要调整;*deleting:配合--delete时,目标独有内容将被删除。
如果预演中出现意外的顶层目录名,通常是源路径末尾 / 写错。
如果几乎所有大文件都显示要重传,应检查两端时间、文件系统时间精度、挂载参数,以及文件是否被应用持续改写。
用脚本串行同步两个目录
需要重复运行时,可以保存为 /usr/local/sbin/sync-two-dirs.sh:
|
|
赋予执行权限并运行:
|
|
脚本使用 set -Eeuo pipefail。
如果第一组 rsync 返回非零状态,脚本会停止,不会把整体任务误报为成功。处理完错误后重新运行即可,已经一致的文件会被跳过。
在 tmux 中运行长时间任务
数 TB 数据可能需要数小时甚至数天。推荐在 tmux 中执行,而不是依赖一直打开的 SSH 窗口:
|
|
进入会话后运行:
|
|
按 Ctrl+b,再按 d,可以让会话在后台继续。
重新连接:
|
|
同时可以从另一个终端观察日志:
|
|
检查进程:
|
|
不要同时启动多个相同脚本。两个任务写入同一块机械硬盘时,并行复制通常只会增加随机寻道和等待时间。
如何确认 rsync 本身正常结束
命令结束后首先检查退出状态:
|
|
0 表示本次运行没有检测到错误,但不能单独证明每个文件内容都经过完整校验。
常见非零状态包括:
| 状态码 | 常见含义 | 处理方向 |
|---|---|---|
11 |
文件 I/O 错误 | 查看内核日志、磁盘和文件系统状态 |
12 |
rsync 协议数据流错误 | 检查远端连接、版本和日志 |
23 |
部分文件未传输 | 搜索权限、消失文件、xattr 和 I/O 报错 |
24 |
源文件在传输中消失 | 判断是否有程序正在移动或删除文件 |
30 |
数据传输超时 | 检查网络、SSH 和超时参数 |
查看日志末尾:
|
|
不要只看终端最后出现了“总字节数”。日志中如果存在 IO error、Permission denied、failed 或 vanished file,仍需判断是否影响验收。
第一层校验:再次执行 dry-run
正式复制后,对两组目录分别运行:
|
|
这里同时使用了 -n,所以 --delete 只会报告目标端多余内容,不会真的删除。
没有输出通常表示:
- rsync 没有发现需要新增或更新的文件;
- 目标端没有源端不存在的额外路径;
- 本次要求保留的常见属性没有差异。
如果输出只有 .rsync-partial/,先确认没有未完成任务。所有同步和校验都结束后,再决定是否清理该临时目录。
如果输出包含 *deleting,说明目标中有源目录没有的文件。先核对这些文件是否应该保留,不要立刻去掉 -n。
第二层校验:读取双方内容并计算校验和
普通 dry-run 主要依赖大小和修改时间,不能排除“大小和时间相同但内容不同”的少见情况。
严格校验可以使用:
|
|
其中 -c 等同于 --checksum。
它会读取双方文件内容并计算校验和,而不是仅比较大小和修改时间。因为同时带有 -n,发现差异时只报告,不修正,也不会删除文件。
对数 TB 数据执行 -c 可能需要很长时间,并对源盘和目标盘产生一轮完整读取负载。
适合使用严格校验的场景包括:
- 原磁盘出现过读错误或掉盘;
- 迁移经过不稳定网络;
- 文件内容非常重要且没有其他校验机制;
- 需要在下线源盘前完成最终验收;
- 怀疑目标文件系统或内存导致静默损坏。
如果磁盘健康状况不佳,先检查 SMART 和内核日志,不要为了校验反复读取濒临故障的磁盘。
第三层校验:比较文件数量和逻辑字节数
统计普通文件数量:
|
|
统计普通文件的逻辑大小总和:
|
|
-xdev 表示不进入目录下挂载的其他文件系统。
如果源目录本来就包含嵌套挂载点,而这些内容也应该复制,就不能直接使用 -xdev,并且要确认 rsync 的挂载点处理策略符合预期。
文件数量和逻辑字节数相等只能作为辅助证据,不能证明路径和内容逐一一致。
du -sh 更不能作为唯一验收依据,因为稀疏文件、压缩、去重、块大小、硬链接和文件系统元数据都会影响实际占用空间。
生成 SHA-256 清单做独立校验
如果希望保存可审计的内容清单,可以在每个目录内部按相对路径计算 SHA-256:
|
|
第二组目录同样处理:
|
|
diff 没有输出且退出状态为 0,表示两份清单一致。
这仍然只校验普通文件内容和相对路径,不验证目录权限、ACL、所有者、硬链接关系或扩展属性。完整 Linux 数据迁移应把它与 rsync -aHAXnc 的结果结合起来看。
检查权限、ACL、扩展属性和硬链接
抽查关键文件的基本属性:
|
|
检查 ACL:
|
|
检查扩展属性:
|
|
检查硬链接文件的 inode 和链接数:
|
|
源端和目标端的 inode 数字不需要相同,但同一端内原本属于一组硬链接的文件,应该共享 inode,并保留正确的链接数。
什么时候才使用 –delete
--delete 让目标最终与源保持镜像关系:目标中存在、源中不存在的路径会被删除。
先做只读预演:
|
|
注意:--delete-delay 也会启用删除语义,只是把实际删除推迟到传输结束阶段。
正式镜像前至少确认:
- 源和目标没有写反;
- 目标挂载点确实在线;
- dry-run 中的每个
*deleting都符合预期; - 目标端没有需要独立保留的文件;
- 已有另一份可恢复备份。
如果希望删除仍可回看,可以先使用备份目录:
|
|
备份目录必须位于空间足够的位置,并且不能放进会再次被同步的源目录树中。
排除回收站和临时目录
NAS 或桌面磁盘中常见一些不需要迁移的缓存目录。仅在确认它们确实可丢弃后添加排除规则:
|
|
'#recycle/' 必须加引号,否则 Shell 可能把 # 后面的内容视为注释。
正式命令和校验命令必须使用相同的排除规则,否则校验时会把有意忽略的内容报告为缺失。
排除规则较多时,保存到文件:
|
|
然后使用:
|
|
控制磁盘和网络负载
在生产服务器上迁移大目录时,可以降低进程的 CPU 和 I/O 优先级:
|
|
跨网络传输还可以限速。远端目标建议直接写出绝对路径,避免混淆本地变量和远端路径:
|
|
本地磁盘到本地磁盘通常不需要 -z 压缩。照片、视频、压缩包也很难进一步压缩,开启 -z 只会增加 CPU 负担。
常见失败与处理方法
Permission denied
先在日志中确认是读取源文件失败、创建目标文件失败,还是设置所有者、ACL、xattr 失败。
|
|
不要直接对整个目标执行宽泛的 chmod -R 777。应检查挂载选项、目标目录所有者和目标文件系统能力。
No space left on device
同时检查容量和 inode:
|
|
大量小文件可能先耗尽 inode,即使 df -h 仍显示有可用容量。
Input/output error
立即查看内核和磁盘状态:
|
|
把 /dev/sdX 替换为实际设备。出现持续读错误时,应先保护仍可读取的数据,不要反复执行全盘校验增加故障盘压力。
file has vanished
状态码 24 通常表示扫描后、复制前,源文件被移动或删除。
缓存、日志和下载目录中偶尔出现这种情况并不罕见。对需要一致性的业务目录,应暂停写入或从快照复制,然后重新运行并确认不再出现消失文件。
所有文件都被再次传输
常见原因包括:
- 目标文件系统不能保留源端时间精度;
- 应用在复制后又改写了文件;
- 源和目标时钟异常;
- 使用了会改变文件属性的挂载方式;
- 文件经过中间程序重新编码或重新打包。
先用 --dry-run --itemize-changes 观察究竟是内容、大小、时间还是权限触发更新。
最终验收清单
完成两个大目录迁移后,至少保留以下证据:
- 两条正式
rsync命令均返回0; - 两份日志中没有未处理的 I/O、权限或空间错误;
- 两组普通 dry-run 都没有意外输出;
- 如需镜像,带
--delete的 dry-run 没有意外删除项; - 文件数量和逻辑字节数相符;
- 重要数据完成
rsync -nc或独立 SHA-256 校验; - 关键文件能够从目标端实际打开;
- 权限、ACL、xattr 和硬链接按业务需求保留;
- 源盘在验收完成前没有被格式化或下线;
- 有条件时完成一次从目标端恢复文件的演练。
最实用的确认命令仍然是:
|
|
它没有输出时,表示在当前排除规则和参数范围内,rsync 没有发现内容、路径或相关属性差异。
对于数 TB 的数据,严格校验很慢是正常现象。不要因为复制命令显示 100% 就立刻删除源数据;复制完成、校验通过和可恢复验证是三个不同的阶段。
常见问题
中断后需要添加特殊的“续传”命令吗?
通常不需要。重新运行相同的 rsync 命令即可。--partial --partial-dir=.rsync-partial 会保留未完成数据,已经一致的文件会被跳过。
两个大目录可以并行复制吗?
技术上可以,但如果它们位于同一源盘或同一目标机械硬盘,并行任务往往会降低吞吐量。默认串行更容易记录、重试和验收。
--progress 和 --info=progress2 有什么区别?
--progress 更偏向显示当前文件进度,--info=progress2 显示整个传输任务的总体进度。超大目录通常后者更便于观察。
为什么复制完成后两边 du -sh 不一样?
文件系统块大小、稀疏文件、压缩、硬链接、元数据和保留块都可能导致占用不同。优先看 rsync 比对、文件清单和内容校验,不要只看 du。
rsync -nc 会修改目标文件吗?
不会。-n 是 dry-run,-c 只是要求根据文件内容校验和判断差异。命令会大量读取磁盘,但不会执行复制或删除。
校验时为什么仍然要写 --delete?
因为只比较源中存在的文件,无法发现目标端多出来的路径。与 -n 同时使用时,--delete 只报告这些额外内容,不会真的删除。
什么时候可以删除源目录?
至少等到两组同步退出状态正常、日志无未解决错误、严格校验通过,并从目标端成功打开或恢复关键文件之后。重要数据还应保留另一份独立备份。