Duplicity 0.8.21 常用 CLI 命令与工具详解
Duplicity 12 个命令动作与 rdiffdir 工具逐一实测:full/incr/restore/verify/collection-status/list-current-files/cleanup/remove 系列/replicate,含失败场景回显与排障处置
Duplicity 0.8.21 常用 CLI 命令与工具详解
目标:逐一实测讲清 Duplicity 的 12 个命令动作(full / incr / restore / verify / collection-status / list-current-files / cleanup / remove-older-than / remove-all-but-n-full / remove-all-inc-of-but-n-full / replicate)与 rdiffdir 伴生工具,每个命令给出真实输入与回显、失败场景与处置方法。回显采集环境为 Ubuntu 22.04 + duplicity 0.8.21(apt 版),与 3.2.2 的动作差异在文中标注。安装见 《Ubuntu 22.04 安装 Duplicity 指南》,选项默认值见 《Duplicity 3.2.2 配置参数详解》。
一、环境信息
- 操作系统:Ubuntu 22.04,x86_64
- Duplicity:0.8.21(
duplicity --version实测输出duplicity 0.8.21) - GnuPG:gpg (GnuPG) 2.2.27
- 演示数据:
/srv/data(docs/readme.txt 文本 + photos/ 下 3 个二进制文件,共 7 个路径条目) - 备份目标:
file:///srv/backups(本地 file 后端;云后端命令形态一致,仅 URL 不同) - 演示密钥:
Backup Demo <root@backup.local>,口令q1w2e3r4
二、工具概览
Duplicity 包内提供两个命令:
- duplicity:主命令,一个二进制承载全部备份动作,动作词决定行为(备份/恢复/查看/清理);
- rdiffdir:目录级差量工具(librsync 的 rdiff 向目录的扩展),生成目录签名与增量,不依赖备份链,apt 包附带(
/usr/bin/rdiffdir),3.2.2 的 pip 安装不再提供。
命令总形态(0.8.21 duplicity --help 实测头部):
Usage:
duplicity [full|incremental] [options] source_dir target_url
duplicity [restore] [options] source_url target_dir
duplicity verify [options] source_url target_dir
duplicity collection-status [options] target_url
duplicity list-current-files [options] target_url
duplicity cleanup [options] target_url
duplicity remove-older-than time [options] target_url
duplicity remove-all-but-n-full count [options] target_url
duplicity remove-all-inc-of-but-n-full count [options] target_url
duplicity replicate source_url target_url
💡 说明:省略动作词时(如
duplicity /srv/data file:///srv/backups)为「智能模式」——目标无全量则自动全量、有全量则自动增量。生产脚本建议显式写动作词,语义更明确。
三、前置条件
- 按安装篇完成安装并通过
duplicity --version验证; - GPG 密钥已生成(或确定用
--no-encryption),PASSPHRASE可用; - 备份源目录存在且有读权限,目标 URL 按后端语法给出(本文用
file:///srv/backups演示,云后端替换 URL 即可)。
准备演示数据(若跟随安装篇已做过,此步可跳过):
mkdir -p /srv/data/docs /srv/data/photos /srv/backups
echo "hello duplicity v1" > /srv/data/docs/readme.txt
dd if=/dev/urandom of=/srv/data/photos/img1.bin bs=1K count=256 2>/dev/null
cp /srv/data/photos/img1.bin /srv/data/photos/img2.bin
四、命令详解
4.1 full:全量备份
完整复制源目录生成一条新备份链的基线,首次备份与定期重建基线都用它:
PASSPHRASE='q1w2e3r4' duplicity full /srv/data file:///srv/backups
实测回显(输出节选,实测首尾):
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: none
--------------[ Backup Statistics ]--------------
StartTime 1792604537.79 (Wed Oct 21 17:42:17 2026)
EndTime 1792604537.94 (Wed Oct 21 17:42:17 2026)
ElapsedTime 0.15 (0.15 seconds)
SourceFiles 6
SourceFileSize 536595 (524 KB)
NewFiles 6
NewFileSize 536595 (524 KB)
DeletedFiles 0
ChangedFiles 0
ChangedFileSize 0 (0 bytes)
ChangedDeltaSize 0 (0 bytes)
DeltaEntries 6
RawDeltaSize 524307 (512 KB)
TotalDestinationSizeChange 526869 (515 KB)
Errors 0
-------------------------------------------------
产物落盘(ls -la /srv/backups 实测):
-rw-r--r-- 1 root root 6624 Oct 21 17:42 duplicity-full-signatures.20261021T174217Z.sigtar.gpg
-rw-r--r-- 1 root root 255 Oct 21 17:42 duplicity-full.20261021T174217Z.manifest.gpg
-rw-r--r-- 1 root root 526869 Oct 21 17:42 duplicity-full.20261021T174217Z.vol1.difftar.gpg
💡 说明:三件套构成一个全量备份集——manifest(清单)、sigtar(签名档,供下轮差量比对)、difftar(tar 格式数据卷),
.gpg后缀为加密标志,文件名内嵌 UTC 时间戳20261021T174217Z。统计中TotalDestinationSizeChange是写入目标的净增量。
4.2 incr:增量备份
基于现有链生成增量集,只记录与上次备份的差异。先修改数据(追加一行、新增一个文件),再执行:
echo 'hello duplicity v2 - changed line' >> /srv/data/docs/readme.txt
dd if=/dev/urandom of=/srv/data/photos/img3.bin bs=1K count=64 2>/dev/null
PASSPHRASE='q1w2e3r4' duplicity incr /srv/data file:///srv/backups
实测回显(统计节选,实测末尾):
Last full backup date: Wed Oct 21 17:42:17 2026
--------------[ Backup Statistics ]--------------
StartTime 1792604546.56 (Wed Oct 21 17:42:26 2026)
EndTime 1792604546.69 (Wed Oct 21 17:42:26 2026)
ElapsedTime 0.14 (0.14 seconds)
SourceFiles 7
SourceFileSize 602165 (588 KB)
NewFiles 2
NewFileSize 69632 (68.0 KB)
DeletedFiles 0
ChangedFiles 1
ChangedFileSize 53 (53 bytes)
ChangedDeltaSize 0 (0 bytes)
DeltaEntries 3
RawDeltaSize 65595 (64.1 KB)
TotalDestinationSizeChange 66142 (64.6 KB)
Errors 0
-------------------------------------------------
💡 说明:本轮实际传输 64.6KB(对比全量的 515KB),增量效率一目了然——新增文件 img3.bin(64KB)计入 NewFiles,readme.txt 的追加计入 ChangedFiles。⚠️ 目标没有全量基线时
incr直接报错拒做(实测):
PASSPHRASE='q1w2e3r4' duplicity incr /srv/data file:///srv/backups-nobase
实测回显:
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: none
Fatal Error: Unable to start incremental backup. Old signatures not found and incremental specified
处置:空目标首次备份改用 full 动作,或用省略动作词的智能模式让其自动全量。
4.3 list-current-files:列出当前备份的文件清单
查看「恢复到最新时刻会得到哪些文件」,不落盘:
PASSPHRASE='q1w2e3r4' duplicity list-current-files file:///srv/backups
实测回显:
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:42:17 2026
Wed Oct 21 17:42:10 2026 .
Wed Oct 21 17:42:10 2026 docs
Wed Oct 21 17:42:24 2026 docs/readme.txt
Wed Oct 21 17:42:24 2026 photos
Wed Oct 21 17:42:10 2026 photos/img1.bin
Wed Oct 21 17:42:10 2026 photos/img2.bin
Wed Oct 21 17:42:24 2026 photos/img3.bin
💡 说明:每行是「权限前的 mtime + 文件路径」,含目录节点本身;配合
-t可查看历史时刻的清单(如-t 7D看一周前)。
4.4 collection-status:查看备份链状态
排障与容量治理的首要命令——显示链条构成、孤儿集与缓存目录:
PASSPHRASE='q1w2e3r4' duplicity collection-status file:///srv/backups
实测回显(输出节选):
Last full backup date: Wed Oct 21 17:42:17 2026
Collection Status
-----------------
Connecting with backend: BackendWrapper
Archive dir: /root/.cache/duplicity/58fb6bfee477db35c5792612a5de2147
Found 0 secondary backup chains.
Found primary backup chain with matching signature chain:
-------------------------
Chain start time: Wed Oct 21 17:42:17 2026
Chain end time: Wed Oct 21 17:42:26 2026
Number of contained backup sets: 2
Total number of contained volumes: 2
Type of backup set: Time: Num volumes:
Full Wed Oct 21 17:42:17 2026 1
Incremental Wed Oct 21 17:42:26 2026 1
-------------------------
No orphaned or incomplete backup sets found.
💡 说明:
Full + Incremental逐行列出当前主链的备份集构成;No orphaned or incomplete backup sets found表示无孤儿/不完整集(若有,用 4.9 节 cleanup 清理)。
4.5 verify:校验备份与源的一致性
PASSPHRASE='q1w2e3r4' duplicity verify file:///srv/backups /srv/data
实测回显(输出节选,实测末尾):
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:42:17 2026
Verify complete: 7 files compared, 0 differences found.
💡 说明:默认比对文件元数据,加
--compare-data会解开数据卷做内容级比对(更慢更彻底)。-t可校验历史时刻(如-t 7D验证一周前状态的完整性)。
4.6 restore:恢复
场景一:整目录恢复。模拟灾难——删除源目录后从备份完整还原:
rm -rf /srv/data
mkdir -p /srv/restore
PASSPHRASE='q1w2e3r4' duplicity restore file:///srv/backups /srv/restore
实测回显:
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:42:17 2026
验证内容完整还原(实测):
cat /srv/restore/docs/readme.txt
实测回显:
hello duplicity v1
hello duplicity v2 - changed line
场景二:单文件恢复(--file-to-restore 取 archive-relative 路径):
PASSPHRASE='q1w2e3r4' duplicity restore --file-to-restore docs/readme.txt \
file:///srv/backups /srv/restore-single-readme.txt
实测回显(输出节选):
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:42:17 2026
cat /srv/restore-single-readme.txt
实测回显:
hello duplicity v1
hello duplicity v2 - changed line
场景三:时间点恢复(PITR)。-t 指定历史时刻,还原该时刻的状态(本轮演示目录含 v1/v2/v3 三版内容,时间点取在只有 v1 的全量完成时刻附近):
rm -rf /srv/restore-t && mkdir -p /srv/restore-t
PASSPHRASE='q1w2e3r4' duplicity restore -t '2026-10-21T17:42:20' \
file:///srv/backups /srv/restore-t
cat /srv/restore-t/docs/readme.txt
实测回显:
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:42:17 2026
hello duplicity v1
💡 说明:
-t接受 ISO 时间串、7D/1M相对量等多种格式(时间格式体系见 《Duplicity 3.2.2 配置参数详解》5.5 节)。恢复到非空目录会报错,需--force覆盖。
4.7 remove-all-but-n-full:按全量条数清理
保留最近 n 条全量链(连同其增量),删除更旧的链。先制造第二条链再清理(实测):
PASSPHRASE='q1w2e3r4' duplicity full /srv/data file:///srv/backups 2>&1 | grep Errors
PASSPHRASE='q1w2e3r4' duplicity remove-all-but-n-full 1 --force file:///srv/backups
实测回显(输出节选,实测末尾):
Last full backup date: Wed Oct 21 17:43:18 2026
Deleting backup chain at time:
Wed Oct 21 17:43:04 2026
Deleting complete signature chain Wed Oct 21 17:43:04 2026
Deleting complete signature chain Wed Oct 21 17:43:04 2026
Deleting complete backup chain Wed Oct 21 17:43:04 2026
清理后目标只剩最新全量链(ls /srv/backups 实测):
duplicity-full-signatures.20261021T174318Z.sigtar.gpg
duplicity-full.20261021T174318Z.manifest.gpg
duplicity-full.20261021T174318Z.vol1.difftar.gpg
⚠️ 注意:清理类命令不带
--force是 dry-run(只打印将删除的清单不动手)。生产 cron 里若忘了--force,清理会静默失效。
4.8 remove-older-than 与 remove-all-inc-of-but-n-full
remove-older-than 按时间删旧链(本演示链均在 1 天内,dry-run 实测):
PASSPHRASE='q1w2e3r4' duplicity remove-older-than 1D file:///srv/backups
实测回显:
Last full backup date: Wed Oct 21 17:43:18 2026
No old backup sets found, nothing deleted.
remove-all-inc-of-but-n-full 保留最近 n 条全量链但删除链内增量(把恢复粒度收敛到全量点,常用于「只要周全量」的归档桶):
PASSPHRASE='q1w2e3r4' duplicity remove-all-inc-of-but-n-full 2 file:///srv/backups
实测回显:
Last full backup date: Wed Oct 21 17:43:18 2026
No old backup sets found, nothing deleted.
4.9 cleanup:清理孤儿与不完整备份集
上传中断、手动误删部分卷后会留下孤儿文件,cleanup 负责回收(无孤儿时实测):
PASSPHRASE='q1w2e3r4' duplicity cleanup file:///srv/backups
实测回显:
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:43:18 2026
No extraneous files found, nothing deleted in cleanup.
💡 说明:发现孤儿文件时会列出清单,同样需
--force才真删。判断依据来自 4.4 节 collection-status 的链分析。
4.10 replicate:备份链跨目标复制
把现有备份链复制到另一个目标 URL(如本地 → 异地对象存储),源链不受影响:
duplicity replicate file:///srv/backups file:///srv/backups-mirror
实测回显(输出节选):
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: none
Replicating b'duplicity-full-signatures.20261021T174318Z.sigtar.gpg'.
Replicating b'duplicity-full.20261021T174318Z.vol1.difftar.gpg'.
复制后目标即拥有可独立恢复的完整链(ls /srv/backups-mirror 实测):
duplicity-full-signatures.20261021T174318Z.sigtar.gpg
duplicity-full.20261021T174318Z.manifest.gpg
duplicity-full.20261021T174318Z.vol1.difftar.gpg
💡 说明:replicate 按备份集清单逐卷复制(日志逐文件打印
Replicating b'...'),保持链条可识别;直接 cp 会打乱时间戳命名并在 collection-status 中被视作孤儿集。目标已有同名链时会交互询问是否覆盖。
4.11 verify 与 restore 的失败场景:口令错误
口令不匹配时的标准报错(实测),排障时先核对 PASSPHRASE:
PASSPHRASE='wrongpass' duplicity verify file:///srv/backups /srv/data 2>&1 | head -7
实测回显:
Local and Remote metadata are synchronized, no sync needed.
Last full backup date: Wed Oct 21 17:43:18 2026
GPGError: GPG Failed, see log below:
===== Begin GnuPG log =====
gpg: AES256.CFB encrypted data
gpg: encrypted with 1 passphrase
gpg: decryption failed: Bad session key
===== End GnuPG log =====
4.12 rdiffdir:目录级差量工具
不依赖备份链,独立生成目录签名与差量(apt 包附带,rdiffdir 无参数运行看用法):
rdiffdir
实测回显:
Error: No arguments found
See the rdiffdir manual page for instructions
生成目录签名与差量(成功时静默无输出,以产物文件为准):
rdiffdir signature /srv/data sig.tar
ls -la sig.tar
实测回显:
-rw-r--r-- 1 root root 20480 Oct 21 18:01 sig.tar
rdiffdir delta sig.tar /srv/data delta.tar
ls -la delta.tar
实测回显:
-rw-r--r-- 1 root root 10240 Oct 21 18:01 delta.tar
patch 子命令把差量应用到另一份目录(rdiffdir patch /srv/data-new delta.tar),本文演示目录未做第二副本,语法见 rdiffdir man 手册。
💡 说明:签名与差量均为 GNU tar 格式,适合「把目录增量搬给另一台已有近似副本的机器」这类点对点同步;完整备份体系内一般用不到它,3.2.2 的 pip 安装已不附带(差异对照见 《Duplicity 3.2.2 配置参数详解》第六节)。
五、注意事项
- 备份链连续性:增量依赖签名链,跳着删卷会让其后时间点不可恢复;清理动作统一走 remove-* / cleanup 命令,不要在对象存储控制台手动删文件。
- 清理命令的 dry-run 语义:remove-older-than / remove-all-but-n-full / remove-all-inc-of-but-n-full / cleanup 默认只报不做,
--force才执行。 - --exclude 模式顺序:include/exclude 按出现顺序先到先得,「白名单」要 include 在前、兜底 exclude 在后。
- restore 到非空目录:需
--force;恢复属主默认还原,非 root 执行恢复加--do-not-restore-ownership。 - 本地缓存目录:collection-status/verify/restore 依赖
~/.cache/duplicity/<hash>缓存元数据;缓存丢失后首轮命令会多一次远端元数据同步,属正常。 - 3.x 动作词差异:3.2.2 中
incr的完整写法是incremental,且每个动作有专属--help-<action>;其余动作名一致。
六、常见问题(FAQ)
Q1:Fatal Error: Unable to start incremental backup. Old signatures not found and incremental specified?
目标目录没有全量基线就执行了 incr(本文 4.2 节实测复现)。首次备份改用 full,或省略动作词让 duplicity 自动全量。
Q2:GPGError: GPG Failed ... Bad session key?
PASSPHRASE 与加密时口令不一致(本文 4.11 节实测复现)。修正环境变量即可;若是换了 GPG 密钥,需要旧钥仍在 ~/.gnupg 才能解开历史链。
Q3:备份统计里 SourceFiles 比预期多/少?
统计口径包含目录节点本身(4.3 节清单可见 .、docs、photos 都计入);符号链接默认按链接本身记录,加 --copy-links 才展开内容。
Q4:--exclude '**/photos' 排除后统计仍是 3 个文件?
排除后剩余 docs 目录节点 + readme.txt + photos 目录节点本身仍计入路径遍历(photos 的内容已被排除,实测 SourceFiles 3);用 list-current-files 恢复视角核对最直观。
Q5:replicate 与手动 copy 的区别? replicate 按备份集清单逐卷复制并校验,保持链条可识别;直接 cp 会打乱时间戳命名并在 collection-status 中被视作孤儿集。
Q6:cron 里清理命令一直没生效?
检查是否漏了 --force(第四节 ⚠️),以及 PASSPHRASE 是否在脚本内正确 source。
七、参考链接
- duplicity 稳定版 man page(动作与选项权威定义):https://duplicity.gitlab.io/stable/duplicity.1.html (查询日期 2026-10-22)
- 官网:https://duplicity.us/index.html (查询日期 2026-10-22)
- GitLab 仓库:https://gitlab.com/duplicity/duplicity
- 本专栏系列:《Duplicity 介绍与选型指南》、《Ubuntu 22.04 安装 Duplicity 指南》、《Duplicity 3.2.2 配置参数详解》