资讯动态

CLI-Anything:用命令行工具包终结重复性杂事,提升开发效率

发布时间:2026/9/28 16:16:42 来源:尧图企业网站定制
做开发这些年我越来越发现一个规律真正让人疲惫的往往不是高难度的技术难题而是那些每天重复、看起来简单、却总要手动来一遍的脏活。CLI-Anything 这个名字听起来有点野心但它想解决的问题其实很具体把散落在各个图形界面里的高频操作统一收敛成一个个可以在终端直接敲下的命令入口。我第一次有这种冲动是看着同事在 Windows 上反复打开同一个后台系统、切换账号、截图、重命名、再传到共享目录整个过程整整三分钟而他一天要重复十几遍。三分钟不算长可当它乘以次数、再乘以每个月的天数消耗的东西就很可观了。CLI-Anything 可以是一套你想长期维护的命令行工具包也可以只是一个组织脚本的规范思路。它不限定语言不依赖某个大平台核心是把“结构化的重复”变成“可复现的命令”。这篇文章我会从为什么需要它讲起到技术选型、仓库搭建、命令规范、踩坑排查最后聊到怎么让它从一个人的玩具变成团队共享的基础工具。无论你是后端、运维、测试还是每天和一堆后台页面打交道的运营、产品、设计这套思路都值得试一试。1. CLI-Anything 到底在对抗什么问题1.1 大脑和注意力经不起频繁上下文切换人的短期记忆大概只能同时装下三到五件事。当你每天早上机械地完成“打开浏览器、输入系统地址、输入账号、跳转、下载、改文件名”这一串动作时你的大脑其实一直在多个上下文之间来回切换地址对不对、账号是不是新的、文件名规格是什么、上传路径是不是这个。任何一个环节被打断整套动作就要从头再来。我自己的体感是这类重复操作一旦超过两周我就会开始想自动化。不是因为我懒而是因为手动操作不仅慢还会出错。最典型的就是文件重命名你永远不知道今天哪个系统会把文件名改成什么样的风格等你手动处理的时候一个不留神就会把日期字段搞错。CLI-Anything 想消灭的不是所有操作而是那些“规则明确、步骤固定、可以直接被脚本描述”的操作。1.2 它不是一个自动化框架而是一层入口协议很多人一听“通用命令行工具”第一反应是去装一个庞大的自动化框架。但 CLI-Anything 的思路恰恰相反它不发明新语言不搞分布式调度不自带图形化编排界面。它只做一件事——给现有的脚本、命令、工具调用提供一个统一的收纳盒。也就是说你原来可能有一个upload.sh有一个open-dashboard.py有一个docker compose down的备忘纸条。CLI-Anything 做的事情是把它们整理到同一个命令命名空间里cli app open、cli file upload、cli dev down。它是一层协议而不是一个引擎。好处很明显底层可以是任何东西Bash、Python、Go、Node.js 甚至一个远程调用只要上层输出统一、参数规范、失败时有清晰报错就能长期使用。1.3 适合谁用不适合谁用我推荐给两类人。第一类是每天有大量固定操作的办公型工程师他们的痛不是不会写脚本而是没有一个地方把这些脚本统一管起来。第二类是团队里的技术负责人可以把团队共用的部署、检查、数据处理命令沉淀下来减少口口相传。但 CLI-Anything 不适合那些追求“零学习成本”的人因为它本质上还是命令行。如果你连终端都不愿意打开那这套方案对你反而是负担。同样探索型任务也不要收编进去。什么叫探索型任务就是每次做法都不一样、结果完全不可预期的事情。这种任务更适合你当场实验而不是抽象成一个固定命令。2. 真正适合收进 CLI-Anything 的几类“杂事”2.1 先给任务分类再决定要不要收编我整理了一套自己的归类方式。只要某件事符合下面任何一条我就会考虑把它写进 CLI-Anything执行频率高、步骤固定、字段可参数化、跨应用联动。我实际维护的命令大致跨越这几个领域。任务类别原来的手动场景CLI-Anything 里的形态窗口和进程管理反复找窗口、点关闭、确认进程是否卡住cli app kill 发版平台、cli app focus 测试服批量文件整理下载目录乱成一团每周手动归档cli file sort --by-type --to ~/Archive剪贴板和文本加工复制一段带格式的内容清洗后又要贴回cli clip clean、cli clip replace 全角 半角浏览器直达和系统跳转每天打开 N 个固定后台页面挨个登录cli web portal morning本地开发和服务管理起服务、看日志、查端口、临时开个 HTTP 服务cli dev up、cli dev logs、cli serve . -p 8080这些任务有一个共同点它们在被反复执行但每次执行之间的差异只有那么一两个参数。比如下载文件夹里的文件类型变了但“归档到按日期分好的目录”这个规则没变。再比如每天打开的后台系统不同账号不同但“读取配置里的账号并打开对应 URL”这个流程没变。2.2 例外清单哪些东西我坚决不往里面放我坚决不收编带破坏性的操作尤其是没有 dry-run 支持的删除。比如“清理三个月前的临时文件”这种命令我宁可每次手动执行也不会把它加到默认命令里。你可以写一个cli file clean --dry-run先打印出要删除的东西再带个--yes强制确认这种我才能接受。另外涉及生产环境关键变更的命令我也不建议直接塞进一个万能 CLI。因为万能 CLI 的定位是“一切皆可跑”使用门槛越低误操作的概率就越高。如果你确实要放也应该加环境判断、二次确认和审计日志而不是一个回车下去直接执行。2.3 一切的底层其实是“结构化重复”本质上CLI-Anything 做的事情就是把“人脑里的临场判断”替换成“配置文件里的明确规则”。手动操作时你在想“这个文件该放哪”脚本执行时你只需要把规则预置进去“PDF 放 docs图片放 images其余放 misc”。一旦规则显式化事情就变得可审计、可修正、可复用。这也是为什么那么多人坚持在团队里推广这种工具。因为当你把一个人的经验写成命令文档和脚本另一个人就不需要重新踩一遍坑。你不需要把每个系统的密码告诉同事只要你把登录逻辑封装好输出统一同事只需要记住cli web open qa这一条命令就够了。3. 选型逻辑怎么搭才不会被工具本身困住3.1 我的默认组合是 Bash 加 Python3 加一个任务执行器先说结论我的默认组合是 Bash 加 Python3再配一个很轻的任务执行器比如just或者纯 Makefile。理由是这套组合在绝大多数服务器和开发机上都有不用额外装运行时。Bash 负责命令组装、流程控制、调用外部程序Python3 负责稍微复杂的文本处理、文件操作、CSV 解析just负责提供命令别名、参数传递和文档输出。这远不是唯一方案。如果你所有脚本都是 Typescript那用npm scripts或者tsx做执行器也很自然如果你喜欢 Gomage这类工具也不错。但我见过太多项目为了“统一语言”而硬把系统脚本全部改写成某个大框架最后光在编译部署上就消耗了大量精力真没必要。3.2 为什么不选大型自动化平台大型自动化平台或者 RPA 工具适合企业级的、跨系统的、需要图形化编排的场景。问题是这类工具的依赖很重不是每个 Linux 开发机上都能轻松跑起来。对个人开发者或者小团队来说CLI-Anything 的价值应该在十分钟内就能体现写一个 Bash 函数加一个入口映射搞定。还有一点命令行工具天然拥有“可 grep 性”。你可以直接把命令写进 CI、写进定时任务、在 SSH 会话里远程执行这些都是图形化自动化工具给不了的。我用重框架做过一个内部工具后来发现每次改逻辑都要重新生成一遍客户端而 CLI-Anything 这套方案里改一个命令只是改一个 30 行的脚本。3.3 跨平台要注意的细节CLI-Anything 这个命令很诚实叫 Anything但实际上跨平台会带来一堆麻烦。如果你只在 macOS 或 Linux 上用那 Bash 脚本基本通吃一旦你要在 Windows 上跑就要区分 PowerShell、Git Bash、WSL 三种环境剪贴板命令、路径分隔符、编码全都不一样。我的建议是别追求一套脚本到处跑而是做一个适配层。比如在lib/env.sh里检测操作系统定义CLIP_GET这个变量macOS 上指向pbpasteLinux 上根据发行版指向xclip或wl-pasteWindows 的 Git Bash 里则调用powershell.exe -Command Get-Clipboard。上层的业务脚本只认$CLIP_GET具体在哪套环境跑由适配层决定。我把环境拆成几个目录核心业务逻辑不掺平台判断杂乱的适配都放底层。这样哪怕某天从 macOS 切到 Linux顶层命令一行都不用改。4. 一个可复现的 CLI-Anything 仓库长什么样4.1 目录骨架先搭起来我把整个项目当作一个真正的软件工程来组织只是没有 IDE 那么复杂。目录结构大概这样cli-anything/ ├── bin/ │ └── cli # 统一入口脚本 ├── commands/ │ ├── app.sh │ ├── file.sh │ ├── web.sh │ └── dev.sh ├── lib/ │ ├── env.sh # 操作系统适配层 │ ├── log.sh # 统一日志输出 │ └── utils.sh # 通用函数库 ├── config/ │ └── config.sh # 全局配置也可以读 config.yaml ├── README.md └── justfile核心是这个bin/cli入口。它不做任何实际的业务逻辑只负责把第一个参数当作子命令名转发到commands/目录里面对应的脚本上。4.2 分发入口的写法我的bin/cli相当朴素用 Bash 写几十行就够#!/usr/bin/env bash set -euo pipefail ROOT$(cd $(dirname ${BASH_SOURCE[0]})/.. pwd) SUB${1:-} shift || true case $SUB in app|file|web|dev|clip) exec $ROOT/commands/$SUB.sh $ ;; help|--help|-h) echo 可用子命令: app, file, web, dev, clip echo 查看具体用法: cli 子命令 --help ;; *) echo 未知子命令: $SUB 2 echo 执行 cli help 查看帮助 2 exit 1 ;; esac这段脚本最重要的部分是exec。它用exec直接替换当前进程保证最后退出码和信号处理都来自真正执行的子命令不会在分发层多包一层导致状态丢失。set -euo pipefail是我所有脚本的标配任何一步失败就直接退出不会硬着头皮往下跑。commands里面的每个脚本则遵循同一套约定第一个参数是小动作的名字第二个参数开始是具体参数支持--help失败时返回非零状态码并向标准错误输出一行能看懂的信息。4.3 一个实际命令的完整示例拿最常用的“打开工作台”来说我要完成的事是读配置里的系统列表逐项打开浏览器标签。脚本长这样#!/usr/bin/env bash # commands/web.sh set -euo pipefail source $ROOT/lib/env.sh source $ROOT/config/config.sh portal_morning() { local entry for entry in ${PORTAL_ACCOUNTS[]}; do local name${entry%%:*} local url${entry#*:} echo [web] 打开 $name - $url open_url $url # 在 macOS 上是 openLinux 上是 xdg-open done } case ${1:-} in morning) portal_morning;; --help) echo 用法: cli web morning;; *) echo 未知子命令: ${1:-} 2; exit 1;; esac配置则放在config/config.sh里# 格式名称:URL用空格分隔 PORTAL_ACCOUNTS( 报表:https://report.example.com 运维台:https://ops.example.com 测试环境:https://staging.example.com )这套结构的好处是你不用记一堆脚本路径也不用去翻廖雪峰的 Bash 教程核心就是“入口 业务脚本 配置”三层。新命令加进来时只需要新建一个commands/xxx.sh然后在bin/cli加一行 case 分支。我做过的项目里维护成本最低的往往就是这种结构。5. 写命令时我会强制加上的几个细节5.1 等等就绪再继续不然一定有脏数据CLI-Anything 最容易出问题的点不是命令本身而是前后步骤的衔接。比如你启动一个本地服务紧接着就去请求接口这个顺序在人的操作节奏里没问题但脚本跑起来服务可能还没监听端口。我一般会用一个wait_for_http函数轮询直到健康检查返回成功或者超时报错。wait_for_http() { local url$1 local max_attempt${2:-20} local i0 while [ $i -lt $max_attempt ]; do if curl -fsS $url /dev/null 21; then return 0 fi i$((i 1)) sleep 1 done echo 等待 $url 超时 2 return 1 }类似的问题还出现在文件系统上你删除一个文件马上又要创建同名目录某些同步盘会有短暂的延迟导致冲突。脚本里有两个操作之间若有强依赖关系我宁可多等一轮也不要让依赖关系暗含在巧合的时序里。5.2 必须有 dry-run否则别让我在机器上跑我前面说过不把破坏性操作直接暴露但更严谨的做法是让命令本身就支持两种模式默认只打印将要做什么加--apply才真正执行。以下载文件归档为例没有 apply 的参数我只会看到“移动到 xxx”的输出执行结果不会改变磁盘状态。为每个命令设计 dry-run 其实成本不高不过就是在每行真正动作的前面套一个条件。但这种设计帮我避免过至少三次“手滑删错目录”的灾难。如果你维护的是通用 CLI我强烈建议把这条写进命令规范里。5.3 输出要比你想的更啰嗦一点但别慌乱命令行工具的日志有个度的问题。默认执行时我要求每个动作前的关键信息都以[模块] 动作描述的形式输出。这既是给用户看的也是给调试时看的。你永远不知道哪天会把cli file sort挂在 cron 里那时你会恨不得每一个细节都被日志记录下来。但输出也不要一条接一条滚动不停。一般我会把当前动作和目标参数打印出来比如“移动到 ~/Archive/2025/08/foo.pdf”然后就安静等待。如果出错了标准错误里再给出一句人话建议比如“目标目录不存在请先执行 cli file init”。5.4 处理特殊字符和路径时别省那点引号很多看似诡异的 bug查到最后都是因为文件路径里有空格。我在脚本里写了一条铁律所有变量引用一律加双引号。移动文件时用mv $src $dst而不是mv $src $dst。文件名中带中文、带空格、带括号都不可怕可怕的是你在一开始就没把它当字符串来对待。printf %s $var而不是echo $var也是我喜欢的习惯尤其当变量可能以-n或者-e开头的时候。这些细节在命令行日常里不容易暴露但一旦落到真正的生产环境就是那种能让人排查一夜的低级事故。6. 最容易翻车的五个地方和一个完整排查过程6.1 我在实践中反复踩到的五类问题第一类是环境变量丢失。你在终端里能跑通的命令放到 cron、放到桌面快捷方式里经常因为缺少PATH配置而直接失败。第二类是剪贴板权限。macOS 里从终端运行pbpaste会被系统询问权限但如果你的命令行工具是通过启动器触发的那个进程的权限会被单独对待看不到 TA 的权限弹窗。第三类是当前工作目录的问题。脚本里只要用了相对路径潜在风险就来了从不同目录触发同一个命令结果完全不同。第四类是编码。Windows 下处理 UTF-8 文件和中文内容简直是重灾区PowerShell 的输出编码经常和文件实际编码不一致。第五类是退出码被吞掉。curl | bash这种管道如果前面成功但后面失败最后退出的可能还是 0导致上层误判。6.2 完整排查链路剪贴板命令在特定场景下失效我挑一个真实的案例来说排查过程这比直接给答案更有价值。前阵子我写了一个cli clip clean命令用来把剪贴板里的文字去掉所有多余空行和全角空格。在终端里执行一切正常可当我把它绑到系统快捷键和全局启动器上时命令频繁出现“剪贴板为空”的错误。我第一步是先复现。直接在终端里运行发现输出正常说明脚本逻辑本身没问题。接着我用启动器触发加了一个诊断模式让它把剪贴板的长度原样打印出来发现读到的是空字符串。这时候排查方向收窄到权限启动器进程读取剪贴板时可能并不拥有 macOS 授予的“读取剪贴板”权限。第二步是查系统设置里的权限列表。在 macOS 的隐私设置中终端这个 App 有剪贴板权限但启动器并没有。不过奇怪的是有些启动器会继承你 shell 环境中的权限有些则不会各家实现不同不能一概而论。第三步我换了一种读取方式不再依赖pbpaste而是调用 AppleScript 或者直接让核心逻辑通过一个带权限的助手进程执行。最后的解决方案更简单我把cli clip clean封装成一个小服务在登录时启动通过本地端口暴露成localhost:7891启动器命令只负责向这个端口发送请求。这样剪贴板读取发生在始终有权限的服务进程里启动器不直接碰剪贴板。这个案例想说明一件事CLI-Anything 的调试要从“触发方式”和“运行环境”两个维度考虑你终端里的成功只是在最理想的情况下成功。排查这类问题先打印出入参、环境配置和中间结果确认问题到底出在权限、路径还是数据格式比反复重试有效得多。7. 从个人玩具到团队基础设施的进阶玩法7.1 把命令变成项目的文档和审批依据CLI-Anything 一旦稳定下来价值就不只是“自己节省几秒钟”。它记录了一套操作逻辑等于团队的操作规范被固化到了代码里。新同事入职发给 TA 的文档不用写“先点这里再点那里”而是直接说“你跑一下cli web morning以后每天早上都用它”。如果团队对某些操作有审计诉求你还可以在lib/log.sh统一加一行记录命令名称、参数、执行时间和当前用户写入本地 JSON 文件。这比手工截图留痕靠谱。我见过有团队甚至拿这份日志当自动化操作的口径表出了问题直接回溯当时执行了什么参数。7.2 加一点 Webhook 和定时任务命令就有了远程形态CLI-Anything 是本地优先的但不代表它不能和其他系统连。我的commands/notify.sh里有几个基于 Webhook 的动作比如命令跑完后往聊天工具里推一条结果。这样我可以把cli file backup放到定时任务里失败时收到通知成功时不需要关注。远程触发也可以很轻量。只要有 SSH 访问一条ssh host cli web portal morning就能解决“人在外面、机器还在公司”的尴尬。别一上来就想着做 Web UI、做个控制台、做消息队列。多数情况下一个能远程调用的命令行入口已经解决掉了 80% 的需求。7.3 我会为它专门留一个“收编日”最后分享一个我坚持了很久的习惯每个月抽一小时回忆过去一个月里哪些操作我手动重复超过了三次。如果三次以上就花点时间写成新命令收进来。这个动作的本质不是写脚本而是反推自己的工作结构你不断把可重复的部分转移到机器上剩下的时间就真的能留给思考和不重复的事情。CLI-Anything 的价值不会在最开始写第一版时显现而是在三个月后你发现自己已经忘掉某个系统后台的手动打开方式、只剩命令还在忠实地执行时感受到那种“被替身接管了杂务”的轻松。我认为它值得长期维护也值得你把身边那些让人厌倦的重复动作一条一条“收编”进去。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑