个人电脑目录同步
这个技能干什么
把用户指定的源目录内容,单向复制到目标目录:
- 第一次执行是全量同步(目标从无到有,或补齐缺的)。
- 之后在电脑开机的情况下每天自动增量同步一次,只搬发生变化的文件。
- 源目录严格只读:本技能的任何脚本都不会在源目录里创建、修改、改名、删除任何东西。
实现方式:一个纯标准库的 Python 引擎 scripts/dirsync.py(同步逻辑)+ scripts/schedule.py(注册每日定时任务)。不需要安装任何第三方包。
三条铁规矩
- 源目录绝不可写。 遇到任何"要不要顺手改一下源目录"的想法,答案都是不要。脚本已内置只读审计,会核对同步前后的源目录元数据。
- 源目录和目标目录必须由人明确指定。 不要猜测、不要从聊天上下文里推断路径,也不要自作主张用「桌面」「文档」这类默认目录。问清楚,让用户确认。
- 首次全量,之后增量。 首次
init会自动做全量;后续由计划任务每天跑增量,也可以随时手动sync。
标准流程
第 1 步:问清两个目录
必须拿到用户明确给的两个绝对路径:源目录、目标目录。缺任一个就停下来问。同时确认两件事:
- 目标目录里如果已经有文件,要告诉用户:
mirror模式下目标里多余的文件会被移进回收站子目录(不是直接删)。若用户不想删任何东西,改用--mode additive。 - 源目录与目标目录不能互相嵌套(一个是另一个的子目录),脚本会直接拒绝——这会威胁源目录安全。
第 2 步:先演练,再落地
如果目标目录已存在且非空,先跑演练,把结果讲给用户听,得到认可再真跑:
python <SKILL_DIR>/scripts/dirsync.py init --source "D:\源目录" --target "E:\备份\源目录" --no-sync
python <SKILL_DIR>/scripts/dirsync.py sync --dry-run
演练只打印"将新增/将覆盖/将移入回收站"的清单,不落盘。确认无误后正式初始化:
python <SKILL_DIR>/scripts/dirsync.py init --source "D:\源目录" --target "E:\备份\源目录" --force
init 会写配置并立刻执行首次全量同步。目标目录是空的、用户也没有别的顾虑时,可以直接 init,不必先演练。
第 3 步:注册每日增量
python <SKILL_DIR>/scripts/schedule.py install --time 12:30
- 时间问用户,默认建议
12:30(午休时段机器通常开着)。 - Windows 走计划任务,带三重触发保障:每天定点、登录后 2 分钟补跑、到点关机则开机后补跑(
StartWhenAvailable)。 - 若计划任务不可用(被安全策略拦截等),脚本会自动退化到「启动项 + 距上次成功同步不足 20 小时则跳过」的兜底通道,并在输出里说明。
- 注册结果必须在最后向用户复述:几点跑、用什么方式、任务名。
第 4 步:验收并交代清楚
python <SKILL_DIR>/scripts/dirsync.py verify # 逐文件哈希深度校验,只读
python <SKILL_DIR>/scripts/dirsync.py status # 配置 + 上次运行结果 + 日志尾巴
verify 必须干净(缺失/内容不同/目标多余都为 0)才算交付完成。最后向用户说明:源目录只读、删除进回收站、日志在哪、怎么改目录、怎么停。
命令速查
统一前缀:python <SKILL_DIR>/scripts/dirsync.py
| 命令 | 作用 |
|---|---|
init --source S --target T [--mode mirror\|additive] |
设定两个目录并做首次全量同步 |
init ... --no-excludes |
清空默认排除规则,连 ~$*、._*、*.tmp 也一起备份 |
sync |
立即执行一次增量同步 |
sync --dry-run |
演练,只打印计划不落盘 |
sync --compare hash |
连"大小和时间都没变但内容变了"的文件也揪出来 |
sync --force-delete |
越过单次批量删除比例护栏 |
sync --log-files all\|none |
逐文件日志策略,默认 auto(变更超过 200 个只记汇总与进度) |
verify |
只读深度校验(逐文件 blake2b 比对) |
status |
看配置、上次运行统计、最近日志 |
--home <目录> |
指定状态目录(默认 ~/.dirsync),可并行管理多组目录 |
定时:python <SKILL_DIR>/scripts/schedule.py {install --time HH:MM | show | trigger | remove}
退出码:0 正常;1 有文件级错误;2 配置问题;3 已有同步在跑;4 安全闸门拦截(此时什么都没动)。
内置的安全机制
向用户解释或自查时可参考(细节见 references/design.md):
- 路径闸门:源/目标相同、互相嵌套、任一方是磁盘根目录,一律拒绝执行。
- 写路径断言:每一次写/改名/删除落盘前都断言目标路径仍在目标目录内,越界立即中止。
- 空源保护:源目录扫出 0 个文件而目标有文件时中止(典型场景:移动硬盘没挂上,盘符变成了别的盘)。
- 批量删除护栏:单次要在目标侧删除的文件超过总数的 20%(且多于 5 个)就中止,需显式
--force-delete。 - 删除不销毁:目标里多余的文件移入
<目标>/_dirsync_trash/<时间戳>/,默认保留 30 天。 - 原子写入:先写同目录临时文件再
os.replace,中途断电不会留下半截文件。 - 中断自愈:进程被强杀遗留的中转临时文件(
.原名.dirsync-<pid>.tmp),下次运行开头自动清扫,且不计入"目标多余"统计。 - 互斥锁:定时任务与手动执行不会撞车,陈旧锁会自愈。
- 只读审计:每次运行前后各扫一遍源目录元数据,若有变化会在摘要和日志里列出(多半是别的程序同时在改,本工具自身不写源目录)。
用户常提的后续需求
- 换源或换目标:
init --source 新源 --target 新目标 --force(会重做一次全量)。 - 只想多备份、不想让目标少文件:
sync --mode additive,或 init 时选 additive。 - 马上同步一次,不等定时:
dirsync.py sync。 - 确认两边真的一样:
dirsync.py verify。 - 停掉每日同步:
schedule.py remove;彻底清理再删~/.dirsync目录。 - 再加一组目录:用
--home ~/.dirsync-2分别管理,互不干扰。
出问题先看
references/troubleshooting.md:文件被占用、权限不足、超长路径、盘符变化、定时任务没触发等。references/design.md:同步算法与安全模型、配置字段、日志与运行摘要格式。
改动后自测
修改脚本后务必回归:
python <SKILL_DIR>/scripts/selftest.py
会在系统临时目录里跑 41 项断言,覆盖首次全量、改/增/删增量、同时间戳内容变化、仅大小写重命名、演练模式、五类安全闸门、批量删除护栏、空源保护、源目录缺失、中断残留清理、累加模式,并逐文件校验源目录在全部操作后是否与操作前完全一致。全绿才算通过。