rsync --backup --suffix=.backup 最稳妥,cp -f 无法实现覆盖时自动备份旧文件,因其无内置备份机制,仅强制覆盖并删除原文件。

直接用 rsync 加 --backup 和 --suffix 最稳妥,cp 本身不支持冲突时自动备份旧文件。
为什么不能只靠 cp -f 实现“覆盖+备份”
cp -f 确实能强制覆盖同名文件,但它会直接删掉旧文件,不留痕迹。你想要的是“新文件覆盖旧文件,但旧文件得存成 .~1~ 或类似后缀”,这超出了 cp 的能力范围——它没有内置的备份机制。
常见错误现象:cp -frap src/ dst/ 执行完发现 dst/ 下的旧文件没了,也没留下任何备份副本。
-
-a是归档模式(含-r -p -l等),不是“自动备份” -
-p仅保留权限/时间戳等属性,和备份无关 - 所谓“先手动备份整个 dst 目录”是前置动作,不是合并过程中的自动行为
rsync --backup 是唯一原生支持覆盖时留备份的方案
它在检测到目标路径已有同名文件时,会把旧文件重命名存起来,再写入新文件。关键靠两个参数协同:
-
--backup:启用备份模式 -
--suffix=.backup:指定备份文件后缀(默认是~,即变成file.txt~) -
-a:保持属性和递归 -
-v:看哪些被覆盖、哪些被备份(调试用)
示例命令:
rsync -av --backup --suffix=.backup /path/to/src/ /path/to/dst/
执行后效果:
- 若
/path/to/dst/file.txt已存在,且/path/to/src/file.txt有更新 → 新文件写入/path/to/dst/file.txt,旧文件重命名为/path/to/dst/file.txt.backup - 若目标不存在对应文件,则直接复制,不生成备份
- 目录结构完全保留,软链接、权限、时间戳等由
-a保障
注意 rsync 路径末尾斜杠的语义差异
这是最容易出错的地方,直接影响“是把源目录本身合并进去,还是把源目录内容合并进去”:
-
rsync -a src/ dst/→ 把src/里所有内容(不含src目录自身)复制进dst/ -
rsync -a src dst/→ 把整个src目录(含子目录)作为子项放进dst/,结果是dst/src/xxx
你要的是“合并内容”,不是“嵌套目录”,所以必须带末尾斜杠:src/ 和 dst/ 都要加。
验证方式:运行前先加 --dry-run 看预览:
rsync -avn --backup --suffix=.backup src/ dst/
备份文件不会无限堆积,需手动清理
rsync --backup 不会自动轮转或删除旧备份,每次覆盖都会生成一个新备份文件。比如反复更新 config.json,就会积累 config.json.backup、config.json.backup.1(如果用了 --backup-dir 配合时间戳)等。
如果你需要自动管理备份生命周期,得额外加脚本逻辑,例如:
- 用
--backup-dir指向独立目录(如/tmp/backup_$(date +%s)),每次运行用新目录隔离 - 用
find /path/to/dst -name "*.backup" -mtime +7 -delete定期清理一周前的备份
真正的复杂点不在命令怎么写,而在于你是否意识到:备份是副作用,不是目的;rsync 的 --backup 只解决“覆盖时留痕”,不解决“备份该保留多久”“哪些文件值得备”“冲突时要不要人工确认”。这些得结合场景补全。











