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

Linux rsync 增量同步怎么避免误删:--delete 预演、排除规则与回滚核对

来源:17golang原创

时间:2026-08-26 08:44:27 164浏览 收藏

凌晨备份任务结束后,目标目录里少了几份刚归档的文件,查看命令才发现同步脚本多了一行 --delete。rsync 的增量传输本身很稳,但它会把“源端没有的文件”理解成目标端应该删除;源目录写错、排除规则漏写,都会把这个判断放大。

要点速览
  • 首次执行带 --delete 的任务,先用 --dry-run 只看删除清单。
  • 源路径末尾斜杠决定同步“目录内容”还是“目录本身”,必须在脚本中固定写法。
  • 临时文件、上传目录等业务数据用明确的 --exclude 规则保护,并保存预演日志。
  • 正式同步后同时核对返回码、文件数量和备份目录,异常时先停任务再回滚。

先把 rsync 的删除范围看清楚

下面用 /srv/releases/ 作为源目录,用 /srv/archive/ 作为目标目录。命令里的源路径带末尾斜杠,表示把 releases 里面的内容同步过去,而不是在 archive 下再创建一个 releases 目录。

rsync -a --delete --dry-run --itemize-changes \
  /srv/releases/ /srv/archive/

--dry-run 不会写入文件,--itemize-changes 会把新增、更新和删除都列出来。输出中出现以 *deleting 开头的行时,先确认这些路径确实应该从目标端消失;只要第一行源路径就不对,后面的清单都没有参考价值。

Linux rsync dry-run 预演中核对源目录、目标目录和删除清单的决策路径

参数设计:先做预演,再决定是否启用 --delete

源路径末尾斜杠不能凭感觉改

/srv/releases/ 同步的是目录内容,/srv/releases 则会把目录本身带到目标端。部署脚本里建议把源目录变量和目标目录变量分开写,并在运行前输出它们,避免环境变量为空时意外指向当前目录。

src='/srv/releases/'
dst='/srv/archive/'
test -d "$src" && test -d "$dst" || exit 2
printf 'source=%s target=%s\n' "$src" "$dst"
rsync -a --delete --dry-run --itemize-changes "$src" "$dst"

把删除操作变成可复核的清单

预演结果不要只在终端里看一眼。把输出写进按日期命名的日志,交接时可以明确回答“哪些文件将被删除、为什么在源端不存在”。如果删除数量明显超过平常,先停在预演阶段。

stamp=$(date +%Y%m%d-%H%M%S)
log="/var/log/rsync-preview-${stamp}.log"
rsync -a --delete --dry-run --itemize-changes \
  "$src" "$dst" | tee "$log"
grep -c '^\*deleting ' "$log"

排除规则要保护业务目录,而不是掩盖误配

例如目标端的临时上传文件由另一个任务管理,就不应该被同步删除,可以显式排除;但排除规则越多,越要在日志和测试目录中单独验证。不要用一个过宽的 --exclude='*' 来“保险”,那会让预演结果失去意义。

rsync -a --delete --dry-run --itemize-changes \
  --exclude='uploads/' \
  --exclude='*.part' \
  --exclude='runtime/' \
  /srv/releases/ /srv/archive/

排除规则按相对源目录匹配。把 uploads/ 写成 /uploads/ 可以表达源目录根下的 uploads;是否需要根限定,要结合目录结构测试,不要直接复制到生产脚本。

错误处理与回滚:正式运行也要留下退路

确认预演清单后,再去掉 --dry-run。为了让被替换的文件能在短时间内找回,可以配合 --backup--backup-dir,并为备份目录设置明确的保留周期。

backup="/srv/rsync-backup/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$backup"
rsync -a --delete --backup --backup-dir="$backup" \
  --exclude='uploads/' --exclude='*.part' \
  /srv/releases/ /srv/archive/
rc=$?
test "$rc" -eq 0 || { printf 'rsync failed: %s\n' "$rc"; exit "$rc"; }

上面的备份只保护被替换或删除的目标文件,不能替代源端快照,也不能证明业务内容完整。正式任务结束后至少抽查一个新增文件、一个更新文件和一个排除目录,并记录 rsync 返回码。

Linux rsync 正式同步后核对删除确认、排除目录和备份回滚的检查路径

常见误区与一份上线前检查表

  • 把空变量当成根目录或当前目录:运行前用 test -ntest -d 检查。
  • 只看 rsync 的退出码:退出码正常只代表传输过程完成,还要核对删除数量与业务目录。
  • 先正式执行再看差异:任何带 --delete 的新任务都应先保留一次 dry-run 日志。
  • 把备份目录放在同步目标里:这样下一轮同步可能再次处理备份文件,备份目录应放在独立路径。
检查项通过标准
路径源、目标均为预期目录,末尾斜杠含义已确认
删除清单dry-run 的 *deleting 路径逐项可解释
保护规则uploads、临时文件等目录完成独立抽查
恢复备份目录可读,异常时有停止和恢复步骤

相关问题

不使用 --delete 能避免误删吗?

能避免“源端缺失导致目标端删除”,但目标端会保留源端已经移走的旧文件。是否启用要看目标目录是不是源端的严格镜像,不能只按命令习惯决定。

--dry-run 会创建备份文件吗?

不会。它只模拟变更并输出计划,真正的备份要在去掉该参数后执行。

发现删除清单异常时先做什么?

先停止正式任务,保存预演日志,检查源路径和排除规则,再从备份目录或源端快照核对,不要用另一条同步命令覆盖现场。

结语

rsync 的风险不在于它会删除,而在于“删除依据”通常没有被复核。把源目标路径、dry-run 清单、排除规则、备份目录和返回码固定成一条流程,--delete 才会从一次性冒险参数变成可以审计、可以回退的运维动作。

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