尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

用CLI-Anything把散装脚本变成交互式命令行门户

发布时间:2026/9/28 16:50:23

资讯中心
01
ARTICLE

用CLI-Anything把散装脚本变成交互式命令行门户

用CLI-Anything把散装脚本变成交互式命令行门户
先说个最近的体会。我电脑里散落着十几个小脚本有的做日志清理有的调接口有的批量改文件每个都是 bash 或 Node.js 写的小工具。一开始还挺得意觉得自动化程度高后来发现维护成本全花在“回忆”上这个脚本有什么参数那个脚本的输出是哪来的一个月不动再拿起时就陌生了。所以当我遇到 CLI-Anything 的时候第一反应是“这名字真敢起”第二反应是——它确实在朝“把一切变成命令行任务”这个方向做实事。这篇就想聊聊这个东西到底是什么、原理怎么走、以及怎么把它真正变成自己的工作台而不是又一个只玩两天的玩具。1. 为什么我最终把所有小工具都收编成了“命令行入口”先说清楚 CLI-Anything 是干嘛的。它的本质是个轻量的命令行交互界面生成器你只要把 bash 函数按约定写好它会自动把这些函数变成带菜单、带选项、带输入提示的交互式 CLI。也就是说原本你要手敲的./xxx.sh --envprod --target10.0.0.1这种命令放进 CLI-Anything 之后会变成选择式、填空式的引导操作甚至还能平台部署成为可被云端调用的 HTTP 接口。听起来很花哨但我认为它真正的价值不在“花哨”而是解决了几个很实际的问题。1.1 脚本散乱之后的维护噩梦我有段时间维护一套部署脚本里面有大量的case分支和硬编码变量。每次发布前都要打开脚本文件逐行看确认某个环境变量是从哪读的。这种“打开文件回忆逻辑”的过程特别烧脑因为你写的代码过了一个月就不再是你写的了更像是别人写的。CLI-Anything 逼你给每个脚本函数写清晰的描述、参数说明和默认值这反而成了一种强迫性的文档化。菜单一打开每个任务旁边就有说明文字不需要再翻代码。1.2 它解决的核心矛盾交互体验与零依赖可能有人会问“这不就是 dialog 或者 whiptail 那种 TUI 吗”确实终端下的表单、菜单工具并不稀奇。但 CLI-Anything 的特别之处在于它是从“函数”出发的不需要你重写整套交互逻辑。你只是把命令拆成一个一个函数用约定好的注释块声明参数它就能自动拼出交互界面。底层原理是 bash 原生的select和read但对使用者来说感知到的是一种“零依赖、低侵入”的接入方式。这一点对运维和日常开发非常友好。很多团队不敢随便给服务器装一堆 Python 库或者 Node 包但 bash 是肯定有的。CLI-Anything 本身就是一份脚本拉下来就能用不需要额外的运行时。这种“一个文件走天下”的调性很对我的胃口。2. 它是怎么做到的从 bash 函数到交互菜单的机制拆解CLI-Anything 之所以能“变魔术”核心套路其实是“注释即定义”。你没看错它在#!/usr/bin/env bash下面识别特殊格式的注释块然后根据这些声明生成对应的界面逻辑。2.1 “魔法注释”驱动接口声明写 CLI-Anything 风格的脚本不需要单独的 YAML 或 JSON 配置文件就是直接在函数上方写注释。比如# command deploy # description Deploy to specified environment # arg env Choice:dev,staging,prod # arg target string The target host # arg timeout number Optional timeout in seconds deploy() { echo Deploying to $env at $target }command表示这是一个可被调用的命令description是菜单里显示的解释arg声明参数的名称、类型和取值范围。它会把 Choice 类型自动渲染成可选项string 类型渲染成输入框number 则做数值校验。我用过之后回过头来想这实际上是“约定优于配置”的典型实践你不需要学习一套外部语法只要在函数注释里加几行标记。2.2 自动推导的运行时行为它会去解析函数名和参数定义然后生成一个全局的“命令注册表”。打开入口后你会看到一个编号菜单输入数字就进入对应参数填写流程。填完后它会拼出完整的命令行执行。这有个额外的好处脚本既可以被人类交互式地操作也可以被其他程序直接以非交互方式调用。因为我写的函数本身就是可接收参数的普通 bash 函数CLI-Anything 只是在上面包了一层“询问”的壳。这种“人和程序共用同一入口”的设计大大减少了使用成本——平时自己用交互式菜单CI 里直接用参数调用。2.3 非交互模式脚本里的另一位指挥官CLI-Anything 还支持把命令作为 HTTP 接口暴露出去。这个功能我一开始觉得有点重但后来发现它非常适合团队内部用的“自助式运维小平台”同事不需要 SSH 到服务器直接打开一个网页填表就能触发部署、清理、导出等任务。你不需要写一个完整的前后端项目因为生成器已经帮你把“表单—参数校验—命令执行—返回结果”整条链路串好了。这种“双重身份”很关键。其实命令行工具常见的困境是做成交互极简但无法程序化调用或者做成纯命令行但门槛太高。CLI-Anything 让你写的同一个函数同时具备这两种形态这种灵活性能直接消解一个团队在工具分发上的很多争论。3. 从零搭一个自己的“CLI 门户”以服务器巡检为例理论讲完直接上实操。我自己的做法是搭了一个叫ops-entry.sh的文件用来集中管理服务器巡检、日志查询、缓存清理这些高频操作。下面把关键步骤展开每一步都写了当时为什么这么选。3.1 环境准备与初始化CLI-Anything 依赖 bash 3.2网络工具 curl 可选。初始化只需要两步curl -sL https://raw.githubusercontent.com/PipedreamHQ/cli-anything/main/cli-anything.sh -o cli-anything.sh chmod x cli-anything.sh然后在你自己的脚本里 source 它source /path/to/cli-anything.sh这个设计思路是CLI-Anything 本身是一个运行时框架而我是给它提供命令。不需要安装到系统 PATH直接通过source把它的函数加载进来。这里有个容易踩的个人习惯问题——建议别在~/.bashrc里全局 source因为你可能多个项目共用不同版本的命令脚本全局加载会造成命名冲突。3.2 写第一个“可交互”命令我拿巡检场景来看。服务器巡检通常做的事情是查磁盘占用、看内存状态、列出最近的登录记录。写成 CLI-Anything 命令就是这样# command check-disk # description Show top disk usage # arg threshold number Warn if usage exceeds this threshold check-disk() { local threshold${threshold:-90} df -h | awk NR1 {gsub(%,,$5); if ($50 threshold) print} }第一版我做得太简单直接df -h全部打出来后来发现生产环境看输出还是要有个“只看超阈值”的能力。加上threshold参数后交互式菜单会让你输入一个数字不输就默认 90。这个“默认值兜底”的习惯值得保留因为团队里总有同事不想思考参数不给默认值就卡在输入框前。3.3 接入“选择型”参数的完整闭环再写一个稍微复杂的重启指定服务。这里很自然会想到用 Choice 类型列出可供选择的服务名# command service-restart # description Restart one of the known services # arg service Choice:nginx,mysql,redis,api-server service-restart() { sudo systemctl restart $service systemctl --no-pager status $service | head -5 }这个命令在 CLI-Anything 菜单里会渲染成一个1) nginx 2) mysql 3) redis 4) api-server的可选项列表基本不会打错字也比直接让人输入完整服务名友好得多。还有一类高频需求是“填一次就记住”比如部署目标地址和分支名。我的做法是把它做成带默认值的 string 参数# command deploy-api # description Deploy api-server from git # arg branch string Git branch to deploy # arg target string Target host, default live deploy-api() { echo Deploying branch$branch to $target }执行时只要回车不输入就会走默认分支。这个习惯能显著降低每天重复输入带来的摩擦。3.4 让脚本具备“程序化调用”能力如果你只看交互模式那 CLI-Anything 跟普通 TUI 工具也没拉开多大差距。真正让它“香”的是同一套函数还能被直接命令行调用。CLI-Anything 会把每个函数同时注册成子命令所以我可以在自己的 crontab 里这样用0 9 * * * source /opt/ops-entry.sh check-disk --threshold 85注意是--threshold这种长选项形式而不只是位置参数。它解析完会设置同名环境变量再调用函数。这个设计很巧妙参数不再依赖位置顺序写脚本的人不用担心第 3 个参数到底是端口还是超时时间。代码可读性和健壮性都提升了。提示在 crontab 里使用 CLI-Anything 命令时记得在命令前面加上source /your/script.sh 因为 cron 环境不会加载你 shell 里的自定义配置。3.5 参数校验失败时的表现CLI-Anything内置了对 Choice、number 等类型的校验。选错了或者填了非数字会直接报错不会带着脏参数往下执行。我是手动bash -n排查脚本语法时注意到这点的那些看似“多管闲事”的校验恰恰是防止线上事故的第一道关卡。建议每个命令都定义好类型别偷懒全用 string。4. 跑起来之后我踩过的几个“暗坑”任何工具用上一个月都会遇到一些边角问题。CLI-Anything 也不例外特别是它毕竟是个 bash 项目很多层面的坑跟 shell 本身的特性纠缠在一起。下面是我觉得比较有代表性的几类。4.1 参数命名与全局变量冲突CLI-Anything 会把命令行参数设置成同名 shell 变量这在交互模式下问题不大但如果你在函数里也用了同名变量做别的事情就会互相覆盖。我有一次写个日志导出函数里面刚好用了个叫output的变量存临时文件路径结果这个函数也被注册成带有output string参数的命令两边直接打架。排查半天才意识到是命名冲突。解决方案是给自己的函数设计一套前缀约定比如o_开头表示内部临时变量arg_开头表示需要暴露给 CLI 的参数。虽然是笨办法但非常有效。4.2 子进程与工作目录的坑多数命令在 CLI-Anything 中是以当前 shell 环境执行但如果你通过 HTTP API 方式调用工作目录就不是原来那个了。我一开始把日志路径写成相对路径./logs在本地跑没问题通过 API 触发总是报找不到文件。后来我改成在函数开头统一执行cd $(dirname $(realpath $0))先固定到脚本所在目录再处理相对路径。所有涉及文件读写的操作都建议这样先僵化再优化。4.3 超时与日志别让“静默挂起”坑了团队通过 HTTP 方式触发时如果前端没做超时控制API 请求会一直挂到后端进程结束。我在团队内使用初期就说所有耗时命令要么加 timeout要么做成异步日志轮询模式。CLI-Anything 本身不做任务持久化所以如果你要跑“重启后再看服务状态”这种长链路建议在命令里自己加后台执行nohup bash /path/to/ops-entry.sh service-restart --service api-server /tmp/ops.log 21 这样前台响应快后台状态也能查。日志路径统一成/tmp/ops.log让排障有固定入口这是个很小但很提升体验的习惯。4.4 macOS 与 Linux 的 bash 差异CLI-Anything 的目标环境是 bash 3.2而 macOS 默认停留在 bash 3.2但很多 Linux 发行版已经到 bash 5.x。语法层面的兼容性还好真正的问题是命令本身比如 macOS 的df输出格式跟 Linux 不一样sed -i的用法也有差异。我本地开发在 mac服务器全是 Linux同一个脚本跑起来效果就对不上。后来干脆在脚本里用uname做了分支按系统类型处理差异。5. 从工具到方法什么该并入 CLI 门户什么不该用了一阵子 CLI-Anything 之后我的感受是它与其说是个工具不如说是一套“命令行入口思维”。但你也不能什么都往里塞。把不合适的任务塞进去反而增加认知负担。5.1 适合并入的典型任务判断标准很朴素**这个任务是不是“参数基本固定、流程相对清晰、重复频率高”**如果三个条件都满足就很适合做成 CLI-Anything 命令。我自己常并入的是这几类服务器巡检磁盘、内存、进程数量日志抓取与关键字过滤服务启停代码发布与回滚定时数据导出简单的数据库查询接口合并之后日常操作基本不用再翻笔记因为菜单就是笔记。就算换了台电脑只要拉下脚本所有“怎么操作”的知识都在里面。5.2 不适合硬塞的场景反过来如果任务是探索式的、需要不停试错的比如分析一段数据、写一个临时查询那就不适合做成固定的 CLI 命令。命令界面再友好也只是一个固定模板探索式工作应该留在 REPL 或者临时脚本里没必要给“一次性任务”固化入口。比较典型的是线上临时排查你根本不知道下一步要看什么文件、执行什么命令。这种情况我更推荐直接打开一个普通终端自由操作。一个比较实用的判断标准如果你发现自己连续三次做同样的事那就值得把它变成一条命令如果只是偶尔一次先扛着别急着抽象。5.3 把它变成团队知识库CLI-Anything 还有一个隐藏价值就是它能“把经验变成可见的选项列表”。比如我处理过一次 Redis 连接数打满的问题处理方式无非就是查看连接数、定位哪个客户端占用最多、临时调大 maxclients、再优化客户端配置。这四个步骤我全部做成了 Choice 型参数的命令团队新人在菜单里按顺序操作一遍就基本掌握了一次标准故障排查的思路。这种方式比写文档有用得多因为人面对菜单时天然会跟着选项走不太容易遗漏步骤、更不会搞乱顺序。文档可能被翻几页就丢但命令行工具是每次出问题都要打开的。6. 分享几个我现在仍在用的模式和思路最后聊几个从 CLI-Anything 发散出来的习惯。这些不是你装一个工具就能得到的而是在实际使用中慢慢磨出来的。第一个习惯给每个命令都写实际的description。CLI-Anything 的菜单展示依赖这段描述你写“Do something”还是写“Show top 5 CPU-consuming processes”差别很大。前者过两个月你自己都看不懂后者让任何人拿起就能用。第二个习惯命令要有“干跑模式”。初期接入的时候我怕误操作生产环境给每个写操作都加了个--dry-run参数打印将要执行的命令但不真正执行。后来觉得这套思路值得保留现在新命令上线前我都会先跑一遍干跑模式给别人看确认没有意外再切换成正式执行。第三个习惯把非交互模式编进 CI。我没有把 CLI-Anything 只当成终端里的东西ci 流程里也直接调用同名函数。这样保证开发、测试、生产三套环境用的是同一份操作逻辑只是参数不同。之前遇到过“运维手册和实际脚本不一致”的惨痛经历现在用这种方式把一致性从源头解决了。第四个也是比较个人向的一个想法探索把 CLI-Anything 和自定义别名结合。我在自己的 shell 配置里给常用的几个命令设置别名比如ops直接打开整个 CLI 菜单。这个别名只是入口真正干活还是由 CLI-Anything 的菜单和参数体系来完整引导。这篇文章并不试图把 CLI-Anything 吹成什么银弹我自己也还在不断调整使用边界。但有一点是明确的当你的“小工具库”开始需要一个统一门面的时候它的确提供了一个成本极低、把交互感拉满的方案。如果你也有一堆散装脚本不妨找个下午给它们加上注释纳入一个门户入口。等下次再有人问你“这个脚本怎么跑”你只需要把菜单截图发过去一切都不言自明。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。