登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux rsync保留权限与删除多余文件的迁移清单

来源:17golang原创

时间:2026-09-20 14:47:55 403浏览 收藏

Linux 上用 rsync 做目录迁移时,保留权限和删除目标端多余文件是两个独立动作:-a(归档模式)负责递归复制并带上权限、时间、符号链接等属性,--delete才会清理由源目录不存在的目标端文件。迁移前先用 dry-run 看删除集合,再决定是否使用删除延迟、删除上限和保护过滤,风险会清晰很多。

要点速览
  • -a等价于一组递归、链接、权限、时间、属主和特殊文件选项,但不自动包含 ACL 与扩展属性。
  • --delete只作用于正在同步的目录;错误的源路径、尾斜杠或过滤规则都可能让删除范围偏离预期。
  • 正式迁移至少保留一次 --dry-run --itemize-changes 记录,并用 --max-delete给异常差异设置刹车。

把权限保留和目标端默认权限分开

-a不是“复制全部元数据”的模糊开关,它通常展开为 -rlptgoD:递归、符号链接、权限、修改时间、属主、组和设备/特殊文件。ACL、扩展属性和硬链接不在这组默认项里,需要按迁移对象另加 -A-X-H,并确认接收端权限足够。

目标常用选项注意点
尽量还原源目录属性-a接收端需要有设置属主、设备等属性的权限
保留 ACL 与扩展属性-aA -X两端文件系统和权限模型要兼容
采用目标端默认权限-a --no-p --no-o --no-g权限结果受接收端 umask 或默认 ACL 影响

如果迁移的是应用目录,建议先明确“运行用户能否读取”和“部署用户能否写入”这两个结果,而不是看到权限数字相同就结束。需要统一模式时可以再加 --chmod,但它改变的是 rsync 计算出来的权限,不能替代 ACL 迁移。

Linux rsync -a 将源目录权限时间符号链接属性映射到接收端的静态结构说明图
图1:rsync 归档属性关系说明图,展示权限保留与目标端默认权限的边界。

先用 dry-run 看清多余文件

--delete的语义是让接收端目录尽量匹配源端,不是“只删除这次传输失败的文件”。它要求你发送完整目录;如果只选了几个文件,目标端其余内容不会自动成为可安全删除的对象。源路径尾斜杠也要确认:/srv/app/表示同步目录内容,而 /srv/app通常会在目标下保留一层 app

# 先只计算变化,不落盘;-i 让权限、时间和删除项更容易被人工核对
rsync -aivn --delete --itemize-changes /srv/app/ /mnt/migrate/app/

# 正式执行前,把 dry-run 输出中的 *deleting 行单独留档
# 确认源目录、目标目录和过滤规则都正确后,再去掉 -n
rsync -aiv --delete /srv/app/ /mnt/migrate/app/

输出里的 *deleting代表接收端发现了源端没有的条目。真正迁移时若源端发生 I/O 错误,rsync 默认会停用目标端删除,以免把一次临时读故障扩大成大面积清理;不要用 --ignore-errors把这个保护轻易关掉。

按删除时机和数量设置刹车

常规同步可使用默认的 --delete-during行为,边传输边按目录处理删除;需要等文件更新结束后再删除时,选择 --delete-delay。如果目标磁盘很紧,可以考虑 --delete-before,但它会增加开始前的扫描和等待。对于生产目录,先加一个删除数量上限更稳妥:

# 第一次正式迁移只允许删除少量差异,超过上限就停止后续删除
rsync -aiv --delete-delay --max-delete=20 \
  --exclude='*.tmp' --exclude='.cache/' \
  /srv/app/ /mnt/migrate/app/

# 用保护规则明确告诉接收端:即使启用 --delete,也不要清掉保留目录
# 过滤语法要在 dry-run 中先观察,避免保护规则同时隐藏了源端文件
rsync -aiv --delete --filter='P /app-keep/***' /srv/app/ /mnt/migrate/app/

--max-delete=20不是回滚机制,而是异常差异的熔断器;超过限制时 rsync 会跳过后续删除并以错误状态结束。脚本应把这个非零退出当作需要人工确认的信号,不要无条件重试。

Linux rsync dry-run delete-delay max-delete和保护过滤共同限制接收端删除范围的静态结构说明图
图2:rsync 删除安全边界说明图,展示预演、数量上限和保护过滤的关系。

迁移结束后的最小核对清单

先抽查三类对象:一个普通文件、一个可执行文件和一个目录。用 stat比较模式、属主、组和修改时间;如果启用了 ACL 或扩展属性,再分别用 getfaclgetfattr抽查。不要只看 rsync 返回 0,还要保留 dry-run 和 itemize 日志,便于解释“为什么目标端少了一个文件”。

# 读取关键属性;这些命令只查询,不改变迁移结果
stat -c '%A %U:%G %s %y %n' /srv/app/bin/runner /mnt/migrate/app/bin/runner
getfacl -p /srv/app/bin/runner /mnt/migrate/app/bin/runner 2>/dev/null
getfattr -d -m- /srv/app/bin/runner /mnt/migrate/app/bin/runner 2>/dev/null

最终清单应包含:源和目标的绝对路径、是否完整目录同步、权限策略、删除数量上限、排除/保护规则、异常退出处理和回滚副本。这样迁移失败时可以先修正边界再重跑,而不是直接把 --delete换成更激进的参数。

常见问题

-a能保留 ACL 和 xattr 吗?

不能默认保证。归档模式包含常见 Unix 属性,但 ACL 和扩展属性要按场景增加 -A-X,并确认接收端支持。

--delete会删除源目录文件吗?

不会。它删除的是接收端同步目录里源端没有的条目;源端删除需要另一个明确的 --remove-source-files语义,不能混为一谈。

为什么 dry-run 没有删除,正式执行却删了?

常见原因是两次命令的源路径、过滤参数或目录内容不同。应保存完整 dry-run 命令和输出,正式执行只去掉 -n,不要顺手改动其它选项。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>