晚上 11 点我躺在床上想起来第二天得带身份证下意识打开手机备忘录新建、输入、关闭全程花了十几秒。第二天还是差点忘了。真正让我记住这件事的不是备忘录也不是后来换过的一堆待办软件而是一个简单到有点丢人的纯文本文件外加一个我随手写的命令行脚本。圈子里管这种作风叫 Caveman不是骂人说的是你花在工具上的心思少得像穴居人省下来的精力全留给真正要做的事。这篇分享适合两类人一类是已经被各种待办软件折腾到心累想找一条永久退路的人另一类是写了几年代码、突然想明白“复杂不等于高效”的人。我会从 Caveman 的设计逻辑讲起然后给你一套可以直接动手搭的极简本地待办系统包括数据格式、核心脚本、全局快捷键、fzf 搜索、跨设备同步以及我踩过的几个坑。看完你大概半小时就能跑通之后是坚持用的问题而不是工具够不够用的问题。1. 为什么“退化”到纯文本反而更快Caveman 的设计逻辑我在把待办工具换成 Caveman 式方案之后最直观的感受是“记录动作”变轻了。原来用专业待办软件最少要等启动、看加载动画、找到正确的列表、点新建、输入、回车五六步起步现在只需要按一下快捷键终端里敲caveman add 给花浇水回车结束。全程两秒以内而且没有一步需要等待。有人会说“记个待办而已慢几秒能怎样”恰恰就是这几秒决定了一个工具能不能坚持用下去。这类现象在软件设计里叫“使用摩擦”摩擦越高你在需要记录的那一刻就越容易放弃。我当年用 Notion 的时候经常觉得“记一条小事不值得打开这个软件”结果漏掉一堆任务。换成纯文本之后随手就写漏记率明显降下来了。Caveman 的设计逻辑可以拆成三条来看。第一本地优先。数据只存在你自己的磁盘上不依赖任何云服务的状态。断网了不影响服务商改版不影响账号过期也不影响。你关掉编辑器文件还在复制一份备份就在。这个特性在现在的软件环境里显得很“原始”但恰恰是这种原始让它耐用。第二单文件存储。整个待办库就是一个tasks.txt没有数据库没有索引没有缓存。备份不再需要“导出”功能复制粘贴就是备份迁移不用“导入”功能把文件拷到新设备就完事。文件可以用记事本打开也可以用 Vim、VS Code、Emacs 打开任何你顺手的工具都能读。第三键盘驱动。命令行工具天生适合键盘操作可以塞进 shell 别名、全局快捷键、定时任务里。鼠标在这套体系里毫无用武之地但换来的是极高的输入效率。为了更直观我做过一个对比维度重量级待办软件Caveman 式纯文本启动到可录入800ms3s基本是 0终端常驻数据归属第三方服务器本地文件迁移成本导出、导入、整理字段复制粘贴一个文件可编程性看平台脸色grep、awk、脚本随便玩长期可读性平台关闭可能全丢任何编辑器都能打开这里不是说重量级软件一无是处团队协作、复杂项目管理确实需要它。但如果是个人待办这种轻量场景Caveman 的方案明显更省心。我个人的看法是工具应该适配你的记录频率而不是让你去适应工具的工作流。2. 从零搭一个 Caveman 式待办系统核心命令与数据格式在动键盘之前先要定数据格式。这一步最容易被忽略但也是最重要的一步。我早年用 Excel 记待办耗费了大量时间维护表格结构用 Notion 记待办又被各种视图、数据库字段绑架。最后我会发现凡是格式复杂到需要想一下“怎么填”的方案都坚持不了太久。Caveman 式格式应该简单到不用看文档也能理解。2.1 先定格式状态 | 创建时间 | 内容我的数据格式长这样一行一条todo | 2025-01-12 09:14 | 给花浇水 todo | 2025-01-12 09:15 | 给客户回邮件 done | 2025-01-12 09:30 | 提交周报为什么用竖线|做分隔符而不是逗号因为任务内容里出现逗号太常见了“需要采购的清单包括 A 和 B”而竖线在日常句子里几乎不会出现。如果将来内容里确实有竖线我会用反斜杠转义但实际用了快一年一次都没碰到过。状态先只设置两个todo和done。不要一开始就想要“进行中”“等待中”“已推迟”这些花哨状态二态模型最简单也足够支撑个人待办。等真正用出需求来再加不迟文本文件的优势就是改一行解析逻辑就行。2.2 核心脚本add / list / done 三件套我写了一个大约 80 行的 Python 脚本逻辑很直白add往文件末尾追加一行list输出所有状态是todo的行并带序号done把某一行从任务文件里挪到完成记录文件里。完整代码如下#!/usr/bin/env python3 caveman.py - 极简本地待办工具 import os import sys import datetime CAVE_DIR os.path.expanduser(~/.caveman) TASKS os.path.join(CAVE_DIR, tasks.txt) DONE os.path.join(CAVE_DIR, done.txt) def now(): return datetime.datetime.now().strftime(%Y-%m-%d %H:%M) def ensure(): os.makedirs(CAVE_DIR, exist_okTrue) for path in (TASKS, DONE): if not os.path.exists(path): open(path, w, encodingutf-8).close() def add(content): ensure() with open(TASKS, a, encodingutf-8) as f: f.write(ftodo | {now()} | {content}\n) print(f已记录{content}) def show(): ensure() with open(TASKS, encodingutf-8) as f: lines f.readlines() active [line for line in lines if line.startswith(todo)] if not active: print(没有待办休息一下吧。) return for i, line in enumerate(active, 1): _, ts, content line.strip().split( | , 2) print(f{i}. {content}{ts}) def done(index): ensure() with open(TASKS, encodingutf-8) as f: lines f.readlines() # 收集所有 todo 行在 lines 中的真实下标 active_index [] for i, line in enumerate(lines): if line.startswith(todo): active_index.append(i) if index 1 or index len(active_index): print(编号越界) return target active_index[index - 1] line lines[target] _, ts, content line.strip().split( | , 2) with open(TASKS, w, encodingutf-8) as f: f.writelines(lines[:target] lines[target 1:]) with open(DONE, a, encodingutf-8) as f: f.write(fdone | {ts} | {content}\n) print(f完成{content}) def main(): args sys.argv[1:] if not args: show() return cmd args[0] if cmd add: content .join(args[1:]).strip() if not content: content input(内容).strip() add(content) elif cmd list: show() elif cmd done: try: done(int(args[1])) except (IndexError, ValueError): print(用法caveman done 编号) else: print(支持命令add / list / done) if __name__ __main__: main()把脚本保存成~/bin/caveman加上可执行权限然后在.bashrc或.zshrc里配一个别名平时敲cm就能用alias cmpython3 $HOME/bin/caveman为什么用 Python 而不是纯 Bash因为 Bash 处理“按行号删除某行并追加到另一个文件”会有很多细节坑比如空文件读写、循环里修改数组、不同 shell 的语法差异。Python 的列表操作更直观几乎每台机器都有解释器跨平台也方便。脚本虽然 80 行但真正核心的只有 show 和 done 两个函数剩下都在处理边界情况。2.3 完成记录的存档逻辑你可能注意到done命令不是把状态改成done而是把那一行从tasks.txt里挪到了done.txt。这个设计有两个好处一是tasks.txt里永远只存在未完成任务list不需要做任何过滤文件不会无限膨胀二是done.txt天然就是你的完成历史月底想统计一下这个月干了几件事直接grep ^done | 2025-01 done.txt | wc -l就出来了。后期如果你想看未完成任务的创建时间和“熬了几天”把列表输出加上时间列就行。数据格式已经留好了这些字段不需要重建结构。2.4 内容里出现多余空格的问题我刚开始用的时候踩过一个不起眼的小坑caveman add 给 花 浇水句子里的连续空格会被原样写进文件显示的时候有点乱。后来在脚本里加了一步清洗把连续空格压缩成单空格。这不是功能需求纯粹是文本洁癖但对日后的 grep 搜索有帮助。具体操作在main()的add分支里加一行正则替换即可这里不展开。3. 实战接入日常流程快捷键、fzf 模糊查询与定时回顾脚本搭好只是第一步真正让 Caveman 好用起来要把它嵌进日常操作流里。我现在的使用频率大概是每天十次以上绝大多数动作不是打开终端再敲命令而是按一个快捷键、呼出终端、输入一句话。3.1 全局快捷键把记录动作压缩到一步我用的是 macOS全局快捷键方案是 Hammerspoon配置很简单核心就一个热键绑定hs.hotkey.bind({cmd, alt}, C, function() hs.execute(/usr/bin/open -a Terminal $HOME/bin/caveman list) end)按Cmd Alt C会打开 Terminal 并执行caveman list。如果你想要“直接新增”改成caveman add就行。注意这里没有用复杂的弹窗交互就是打开终端、跑命令因为终端本身就是最好的输入框。Linux 用户可以用 i3 或 xbindkeys 绑定任意组合键Windows 用户用 AutoHotkey原理都是“全局键 - 启动终端 - 执行命令”。这一步很重要工具必须出现在你最顺手的位置否则你还是会回到备忘录。3.2 用 fzf 做历史任务模糊搜索任务多了以后list输出的行会变长肉眼找一条旧任务很痛苦。这时候 fzf 才是真正的搜索神器。我常用的两个命令是cat ~/.caveman/tasks.txt | fzf # 在未完成任务里搜 cat ~/.caveman/done.txt | fzf # 在完成记录里搜fzf 支持交互式模糊匹配输入几个关键字候选行会实时过滤。配合--delimiter参数可以只显示内容列cat ~/.caveman/tasks.txt | fzf --delimiter| --with-nth3这样列表里干干净净只有任务内容不会被todo | 日期干扰。选中后直接回车打印那一行然后可以复制内容、编辑、或者继续做下一件事。fzf 的亮点在于无侵入性它不是 Caveman 的一部分而是一个独立的命令行工具只是恰好能和我们这个文本文件无缝配合。这正好体现纯文本格式的好处任何工具都能接进来。3.3 定时回顾在门口放一面待办墙个人待办系统最怕的就是“记了但从来不打开”所以我在 cron 里放了一个每日回顾任务。比如每天 21:30 执行30 21 * * * /home/user/bin/caveman list /tmp/caveman_daily.txt notify-send 今日待办 $(cat /tmp/caveman_daily.txt)macOS 没有notify-send可以用osascript -e display notification ...代替或者干脆打开终端弹一下作用都一样。我自己的做法更原始cron 把待办写入一个临时文件然后屏幕会通过终端窗口弹出来。不需要弹出通知中心因为通知太容易被打断弹一个终端窗口反而更扎眼。这里要提醒一句cron 里执行脚本最好用绝对路径因为 cron 环境变量的搜索路径很窄直接用caveman很可能提示找不到命令。我当时就因为这个卡了半小时最后写成/home/user/bin/caveman list才跑通。4. 跨设备与备份Git 私有仓库与自动提交纯文本的好处是不用专门做备份但只要想换电脑、想在手机上看一眼待办就涉及跨设备同步。我采用的方案是 Git。4.1 用 Git 把数据变成可回溯的版本流我给~/.caveman目录初始化了一个 Git 仓库每次改动提交一次cd ~/.caveman git init git add tasks.txt done.txt git commit -m update $(date %F %H:%M) git remote add origin 你的私有仓库地址 git push为什么要用 Git因为对于纯文本来说Git 就是最天然的版本管理工具。误删了任务git log看一眼git checkout能恢复任意历史版本。哪天想回看三个月前做了什么事直接在历史记录里翻。这些能力都是免费的不需要额外服务。4.2 多设备冲突从根上规避比解决更聪明Git 同步最怕冲突。我一开始天真地以为两个设备同时改一个文件很安全结果有一次手机端和电脑端同时添加任务git pull直接报冲突文件里冒出一堆标记清理了半天。后来我想了一个更稳的办法按日期分文件。每天的待办写到tasks-2025-01-12.txt读取时用cat tasks-*.txt合并展示。这样同一时刻只可能有“一台设备”在写“当天”的文件其他设备即使打开也是只读状态冲突概率大幅下降。脚本只需要小幅改动把打开的文件名改成带日期的版本。这个方案不是万能的比如你在电脑上补记昨天漏掉的任务理论上手机也开着同一份文件还是可能冲突。但实际使用中这种“补记当天”的碰撞概率极低比所有设备都写同一个文件的方案稳得多。4.3 自动提交让备份变成习惯我可以在.bashrc里配一个终端快捷键提交但更可靠的是定时任务。我用了两个任务# 每天清晨自动提交当天数据 0 6 * * * cd ~/.caveman git add -A git commit -m nightly backup git push千万不要在脚本里自动git pull。自动合并的结果往往是两边的记录混在一起你都不知道哪个文件是什么状态。我的原则是推送失败就先停下来手动检查晚上回到电脑前再按一次命令。工具链越简单出错时的排查范围就越小。如果你把数据放在云端盘里比如 iCloud 或某网盘的同步文件夹也可以不折腾 Git直接让云盘替你同步。区别在于云盘同步是“最后一次写入生效”没有版本历史误删就真没了Git 至少能救回来。我个人更推荐 Git因为它连几年的记录都留着——这属于“看不见的价值”等哪天真需要恢复历史时你会感谢当初的决定。5. 我自己踩过的坑中文输入、状态机与“过度自动化”用了大半年踩过不少坑挑三个最值得说的讲讲。这三件事让我反复确认了一点Caveman 的精髓不是“简单到能跑”而是“简单到不需要维护”。5.1 中文输入法导致第一个字符丢失这是我被坑得最莫名其妙的一次。在终端里输入caveman add 买牛奶回车后任务内容经常变成“买牛奶”少一个字比如变成“牛奶”或者“买奶”。排查了半天发现问题出在中文输入法的组合态上当输入法处于中文模式某些终端模拟器会把第一个汉字的一部分当成组合按键吞掉。严格说这是终端和输入法的问题不是即插即用脚本本身的问题但它直接影响使用。解决方式很简单把参数整体用引号包起来caveman add 买牛奶或者干脆在脚本里走交互式输入先输入caveman add回车再通过read读取内容。我的脚本里之所以保留content input(内容)这个分支就是给所有遇到输入法问题的用户留一条退路。5.2 状态机是最大的功能陷阱我一开始觉得光有 done 太粗糙了于是往脚本里加了一堆状态doing、waiting、next、someday。结果用了一个礼拜就疯了每次记录都要想“这个任务到底是 waiting 还是 someday”记录成本直线上涨最后任务没做完先研究起分类学了。这是个很普遍的心态“功能多一点会更完整”但在个人待办这种事上二态模型才是最优解。未完成就是未完成完成了就是完成了别让用户去定义“等待中”和“推迟中”的区别。真要说“这件事今天不做”直接删掉或者用#注释掉那一行日后想找还能翻到。5.3 过度自动化脚本比任务还多我曾经花了一个周末给脚本加了自动排序、日期解析、明日待办自动生成、历史完成率曲线最后写到大半夜。第二天冷静下来发现自动排序会打乱我手动调整的优先级日期解析对中文日期处理出错完成率曲线根本没人看。这些功能不但没有提高效率反而让一个纯文本文件变得不再纯粹。那次之后我立了一个规矩一个功能如果要写超过 20 行代码就先不去做人工操作两周确认它真的是高频需求再说。实际结果是我砍掉了一大半没用的功能留下来的只有 add、list、done、fzf 搜索和 git 备份。这些已经足够支撑每天数十次记录而且我几乎没有再为了“工具本身”花过时间。6. 从待办到随手记Caveman 思路的进一步扩展Caveman 这套“纯文本 简单命令”的思路不止能管待办还能延伸到随手笔记、日志和复盘。数据量大了以后好处反而更明显你可以用命令把自己平时的记录串起来。6.1 把流水账变成自动时间轴我用 Caveman 的方式写日记每天一个 Markdown 文件放在~/.caveman/journal/下。文件名就是日期比如2025-01-12.md记录时只要一条命令echo - $(date %H:%M) 去银行办完柜台业务 ~/.caveman/journal/2025-01-12.md时间一长这个目录就是一个原始但忠实的时间轴。想找上个月某天下午做了什么直接打开对应文件想搜索“银行”这个关键词grep 银行 ~/.caveman/journal/ -r一秒出结果。不需要任何笔记软件的搜索索引文件系统本身就是搜索引擎。当然这非常适合“记录事实”不适合“组织知识”。如果你需要建立知识网络还是老老实实用笔记软件但如果只是怕遗忘Caveman 式日志比什么软件都好用。6.2 周回顾用统计代替看板我以前很喜欢看各种待办软件的统计图完成率、图表、日历方块。后来发现真正驱动复盘的其实只要一个数字——这周完成了几件事。一行命令就够了grep ^done | 2025-01- ~/.caveman/done.txt | wc -l如果这个数字连续几周越来越低就说明计划安排出了问题而不是更需要一个更好看的图表。把统计维度降到最低之后我反而更容易发现问题。每周复盘时再打开journal目录扫一眼哪些天做了什么事一目了然。6.3 给同样喜欢极简方案的人三个建议最后分享三个经过验证的建议。第一条不要在第一周就把所有功能搭完先用最冷启动的 add/list/done 跑一段时间让真实需求自己浮出来。第二条文本文件的编码永远使用 UTF-8尤其是 Windows 上记事本那种带 BOM 的格式会让脚本解析崩溃别问我是怎么知道的。第三条每件待办都用动词开头写清楚动作对象比如“给客户发合同”“给花浇水”模糊的任务最后都会变成拖延的理由。我个人在实际使用 Caveman 式方案时最大的体会是极简不是功能少而是没有多余的东西来消耗你的注意力。文件就放在磁盘上命令三只手数得过来历史记录用 Git 管着不管过多久拿出来都能看懂。这套方案我用了快一年没有换回去的想法也没再为“该用什么工具”纠结过。如果你也想试试不用改脚本先建一个tasks.txt把今天最要紧的三件事写进去然后照着list和done用起来剩下的交给习惯。
阅读完成 · 觉得有帮助?