rclone 操作日志标志详解:用 --differ、--match、--combined 与 --dest-after 记录同步差异与结果
本篇技术指南围绕 rclone 的操作日志标志(Logger Flags)展开:--differ、--missing-on-dst、--missing-on-src、--match、--error、--combined 与 --dest-after。这些标志让 sync/copy/move/copyto/moveto 在传输过程中把每个文件的比对结论与目标端最终状态写入报告文件,是审计同步变更、预判结果的关键手段。读完本文,你能掌握每种标志的输出格式、符号(sigil)语义、--dest-after 的 lsf 格式参数,并能结合 operationsflags 源码 理解其写入时机与已知限制。
一、Logger Flags 是什么:把比对结果落盘为报告
Logger Flags 是 rclone 文件传输类命令的一组通用 CLI 标志。每个标志接收一个文件路径作为参数(传 - 表示输出到 stdout),在命令执行期间把符合该类别的文件路径逐行(one per line)写入对应文件。它们的设计目标是让一次同步操作产生可追溯的文本报告,而不仅是终端日志。
从源码看,这些标志统一定义在 operationsflags 包,并由五个命令注册使用:rclone sync(cmd/sync/sync.go)、rclone copy(cmd/copy/copy.go)、rclone move(cmd/move/move.go)、rclone copyto(cmd/copyto/copyto.go)和 rclone moveto(cmd/moveto/moveto.go)。各命令的 init() 中调用 operationsflags.AddLoggerFlags 注册标志,并在运行时调用 operationsflags.ConfigureLoggers 打开输出文件:
// cmd/sync/sync.go 中的注册模式(其他四个命令相同)
var (
loggerOpt = operations.LoggerOpt{}
loggerFlagsOpt = operationsflags.AddLoggerFlagsOptions{}
)
func init() {
cmdFlags := commandDefinition.Flags()
operationsflags.AddLoggerFlags(cmdFlags, &loggerOpt, &loggerFlagsOpt)
loggerOpt.LoggerFn = operations.NewDefaultLoggerFn(&loggerOpt)
}
二、五个按类别输出的标志
以下标志各把符合条件的路径一行一条写入指定文件(- 为 stdout),输出内容由各标志的帮助文本界定(见 operationsflags.go 第 54-61 行):
| 标志 | 含义(源码帮助文本) | 写入内容示例 |
|---|---|---|
--differ FILE |
Report all non-matching files to this file | 源与目标都存在但内容不同的路径 |
--missing-on-src FILE |
Report all files missing from the source to this file | 只存在于目标端(源端缺失)的路径 |
--missing-on-dst FILE |
Report all files missing from the destination to this file | 只存在于源端(目标端缺失)的路径 |
--match FILE |
Report all matching files to this file | 源与目标一致的路径 |
--error FILE |
Report all files with errors (hashing or reading) to this file | 读取或哈希出错的文件路径 |
--differ 是最典型的一个:它会写入所有“在源和目标上都存在但不同”的路径。
三、--combined:类 diff 的综合报告
--combined 标志把所有文件路径连同前导**符号(sigil)**和空格一起写入一个文件(或 stdout),形似 diff 文件:
| 符号 | 含义 |
|---|---|
= path |
在源和目标上都找到且内容相同(Match) |
- path |
在源端缺失,即只存在于目标端(MissingOnSrc) |
+ path |
在目标端缺失,即只存在于源端(MissingOnDst) |
* path |
源和目标上都有但内容不同(Differ) |
! path |
读取或哈希源端/目标端时发生错误(Error) |
这些符号在源码中是一组 Sigil 常量(fs/operations/logger.go 第 57-65 行):
const (
MissingOnSrc Sigil = '-'
MissingOnDst Sigil = '+'
Match Sigil = '='
Differ Sigil = '*'
TransferError Sigil = '!'
Other Sigil = '?' // reserved but not currently used
)
默认写入逻辑由 NewDefaultLoggerFn 实现(logger.go 第 111-145 行):每个 sigil 对应一个 io.Writer,按 sigil 路由写纯路径;若设置了 --combined,则额外以 "%c %s\n"(符号 + 空格 + 路径)写入综合报告。写入受互斥锁保护,保证并发传输下报告行的完整性。
四、--dest-after:预测目标端同步后的最终清单
--dest-after 写出一份列表文件,格式与 lsf 命令完全一致(包括哈希、修改时间等可定制选项)。概念上它类似于 rsync 的 --itemize-changes,但并不相同——它输出的是命令执行完毕后目标端应当呈现的准确清单,因此本质上是一份预测性结果清单。
4.1 控制输出格式的配套标志
为支持 --dest-after,AddLoggerFlags 还注册了一组沿用 lsf 语义的标志(operationsflags.go 第 63-73 行):
| 标志 | 默认值 | 说明 |
|---|---|---|
--format |
p |
输出格式字符串,格式字符含义同 lsf;h 生效时用 --hash 指定的哈希 |
--timeformat |
2006-01-02 15:04:05(帮助文本) |
自定义时间格式;取 max 时按目标后端的精度自动选择(见下文) |
--separator |
; |
格式项之间的分隔符 |
--dir-slash |
true |
目录名追加斜杠 |
--hash |
MD5 |
使用 h 格式字符时的哈希算法,可选 MD5/SHA-1/DropboxHash |
--files-only |
true |
仅列出文件 |
--dirs-only |
false |
仅列出目录 |
--csv |
false |
CSV 输出(未显式指定 --separator 时默认改用 ,) |
--absolute |
false |
路径前加 / |
格式字符的解析见 LoggerOpt.SetListFormat(logger.go 第 305-364 行),支持的字符与 lsf 一致:p(路径)、t(修改时间)、s(大小)、h(哈希)、i(ID)、m(MIME 类型)、e(加密名)、o(原始 ID)、T(存储层级 Tier)、M(元数据);出现未知字符会打印 unknown format character 错误。
关于 --timeformat max:ConfigureLoggers 中检测到该值时,会调用 operations.FormatForLSFPrecision(fdst.Precision()) 依据目标后端的精度自动选择纳秒级时间格式(operations.go 第 2407 行 起)。
4.2 预测机制:WinningSide
--dest-after 的每一行并非简单记录,而是由 WinningSide 函数对每个文件做“胜者推断”(logger.go 第 202-303 行):它根据 sigil 类型与当前全局配置(ci.DryRun、ci.SizeOnly、ci.CheckSum、ci.IgnoreTimes、ci.IgnoreExisting、ci.Immutable 等)判定同步结束后目标端应保留源端对象还是目标端对象,再通过 PrintDestAfter 按 lsf 格式输出该对象。例如:
MissingOnSrc(目标端独有):若处于DryRun或 copy 类命令(DeleteModeOff),目标对象保留;否则将被删除,报告中不出现;Match且启用了--size-only/--checksum/--ignore-size等标志时,目标对象被视为“胜者”(差异被标志忽略);- 任何
DryRun场景下,除目标端缺失项外目标对象保持不变。
五、写入时机:执行中逐文件记录,而非执行后汇总
文档特别指出:这些日志标志是**在执行过程中(during execution)**对每个文件即时记录的,而不是执行结束后统一生成。因此它们最适合作为“每个文件应当发生什么”(SHOULD happen)的预测器,实际结果(DID)可能与预测不完全一致。
从源码调用链可以印证这一点:
- 命令初始化时通过
WithSyncLogger/WithLoggerOpt把LoggerFn存入context.Context(logger.go 第 147-185 行); - 文件比对函数
equal()在判定大小、哈希、修改时间的每一步就回调 logger,写入Differ或Match(operations.go 第 247-360 行); - 同步引擎在执行复制、删除、错误处理时回调
MissingOnSrc、MissingOnDst、TransferError(fs/sync/sync.go 第 388-1338 行 等多处)。
也就是说,报告行产生的时刻正是传输引擎做出“这个文件需要传输/跳过/删除”决策的时刻。
六、--no-traverse 下的行为退化
当 --no-traverse 标志被设置时,目标端不会做完整遍历,所有“仅存在于目标端”的文件都会缺席于比对视野。文档明确说明:此时涉及目标端独有文件的日志将不完整或完全缺失。源码中 ConfigureLoggers 会主动打印三条针对性警告(operationsflags.go 第 135-144 行):
--no-traverse does not list any deletes (-) in --combined output:--combined输出中不会出现任何-(删除)条目;--no-traverse makes --missing-on-src produce empty output:--missing-on-src输出为空;--no-traverse makes --dest-after produce incomplete output:--dest-after输出不完整。
因此需要目标端独有文件信息的报告(- 符号、--missing-on-src、--dest-after 的准确性)时,应去掉 --no-traverse。
七、已知限制(Limitations)
这些日志标志存在若干尚不支持的场景(文档与 WinningSide 的源码注释 一致列出):
--max-duration/CutoffModeHard:硬性截止时间中断传输时,无法可靠预测哪些传输完成;--compare-dest/--copy-dest:因为同一文件的equal()会被多次调用,产生重复/失真记录;- 一次性 server-side 移动整个目录:引擎拿不到目录内单个文件对象,逐文件记录缺失;
- 高层重试(high-level retries):重试会造成报告中出现重复条目,如需规避可加
--retries 1禁用重试; - 一些不寻常的错误场景(possibly some unusual error scenarios)。
此外再强调一次定位:报告是执行中的逐文件预测记录,实际结果可能因错误、重试或外部变更而与报告不同。
八、实战用法
以下命令均可直接复制运行(以本地与远端 remote 为例):
# 综合差异报告:所有文件带符号写入 report.txt
rclone sync /data/src remote:dst --combined report.txt
# 只要“两边都有但不同”的文件列表,输出到终端
rclone sync /data/src remote:dst --differ -
# 分别收集四类结果
rclone copy /data/src remote:dst \
--match same.txt --differ changed.txt \
--missing-on-dst added.txt --error errors.txt
# 预测同步后目标端的完整清单(路径+大小+ID,分号分隔,含目录时注意 --dirs-only 默认 false)
rclone sync /data/src remote:dst \
--dest-after after.txt --format ps --separator ";"
# CSV 格式 + 按目标端精度最大化时间格式(此时 --timeformat 仅对 t 字符有意义)
rclone sync /data/src remote:dst \
--dest-after after.csv --format pt --csv --timeformat max
# 干跑(--dry-run)下同样可用:--dest-after 会反映 DryRun 结束后“不变”的目标端状态
rclone sync --dry-run /data/src remote:dst --dest-after after-dry.txt --format p
使用要点回顾:
- 五个分类标志各自独立,可任意组合,
-表示 stdout; --combined是唯一带符号的汇总报告,符号语义见第三节的Sigil常量;--dest-after输出即lsf格式,可用--format、--separator、--csv、--hash、--absolute等标志定制(见第四节参数表);- 避免与
--no-traverse、--compare-dest/--copy-dest、--max-duration(Hard 模式)及默认多层重试混用,否则报告不完整或含重复。
相关源码与文档
- 标志定义与文件打开逻辑:operationsflags.go
- 文档原文(嵌入命令帮助文本):operationsflags.md
- 符号常量与预测逻辑:logger.go
- 比对时的记录点:operations.go、同步引擎记录点:sync.go
lsf格式参考:rclone_lsf.md
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00