做开发这些年,我越来越发现一个规律:凡是让我重复劳动超过三次的操作,最后可能都被我搬进了终端。这个习惯后来沉淀成了一套对内的工具集方案,我管它叫“CLI-Anything”——不是指某个具体的软件,而是一种覆盖文件处理、数据解析、接口调试、容器运维和系统监控的全场景命令行工作流。简单说,能一条命令说清楚的事,绝不打开图形界面点来点去。
这篇文章我会分享一下CLI-Anything的整体思路、工具选型、具体配置脚本,以及我在真实项目里踩过的一些坑。它不是一份简单的“好用的命令行工具推荐”,而是一套可以照着搭建的完整工作流实践。适合想要提升日常开发效率、愿意花一点时间配置终端环境的人,无论你是后端、前端还是运维,这套东西都能直接把你的操作速度拉高一个档次。
1. 需求拆解:为什么要把一切搬到命令行
1.1 一切皆可脚本化的底层逻辑
先聊一个问题:GUI和CLI的本质差别到底在哪?
GUI给我们的是一种“可视化反馈”,但它的致命弱点是不可重复、不可组合、不可审计。你用鼠标画一个框,拖一个文件,这个过程本身不能被记录下来,下次还得重新手工操作。而CLI的核心是文本流,输入和输出都是纯文本,这意味着什么?意味着操作可以被复制、被修改、被管道串联、被脚本固化。
举个最直观的例子。假设你有一个目录,里面有一千张图片,要按拍摄日期重新命名。用GUI做,哪怕你再熟练,也得打开文件管理器,逐个查看属性、手动改名,至少得折腾半小时。用命令行,一条find加exiftool就能搞定,哪怕你从来没写过这条命令,从搜索到跑通,十分钟以内也能完成。这就是可组合性的力量。
所以CLI-Anything背后真正的逻辑不是“命令行比图形界面酷”,而是:任何有明确规则、可重复执行的电脑操作,都应该被写下来,而不是被点出来。
1.2 什么场景适合CLI,什么场景不适合
当然,不是所有事都该硬塞进终端。我自己的判断标准是这样的:
- 适合CLI:批量文件操作、日志检索、数据格式转换、API调试、远程服务器管理、定时任务、代码构建、版本仓库操作、容器生命周期管理。
- 不适合CLI:复杂的图片精修、视频非线性剪辑、原型布局设计、需要多人实时协作的白板类任务。
一个常见的误区是“万物皆可终端”,结果把小半天时间耗在折腾一个本来不值得的命令上。我见过有同事为了用终端看图非要装一堆图像渲染插件,折腾了一个小时,最后发现还是用系统自带的预览器更快。CLI-Anything的真正原则是:对有规则、可重复的事情做脚本化,对一次性、视觉化、强交互的事情大胆交给GUI。
1.3 工具选型的三条标准
既然是一套工具集方案,选型标准就很重要。我在沉淀CLI-Anything时只遵循三条原则:
第一,专注单点功能。一个工具只把一件事做到极致。文本搜索就用rg,文件查找就用fd,JSON解析就用jq,不要去用那种缝合怪式的万能工具,缝到最后什么都很平庸。
第二,跨平台兼容或可替代。ls在Linux和macOS上的参数就有差异,sed和awk的GNU版本和BSD版本行为也不同。选型的时候就要想清楚,这套方案以后会不会在别的机器上跑,遇到差异怎么处理。
第三,原生支持管道和stdin/stdout。CLI工具的价值全部在于与其他工具协作,如果一个命令不支持标准输入输出,那它在这个体系里就是孤岛,价值大打折扣。
顺着这个标准往下走,工具清单自然就浮出来了。
2. 核心工具拆解:按场景搭建命令行工具箱
2.1 文件系统与文本内容:fd、fzf、rg、jq
文件操作是终端里使用频率最高的场景。很多人习惯用find去搜文件、用grep去搜内容,它们当然能用,但效率和体验都有点老旧。我在CLI-Anything里首选的是这几个:
fd:一个比find更快、更符合直觉的文件查找工具。它默认可识别.gitignore规则,也就是说你搜项目文件时,node_modules这类目录会被自动排除,不用手动写-not -path。它还支持正则表达式,fd -e md可以只搜Markdown文件。rg(ripgrep):代码内容搜索的神器。它的速度比grep快得多,因为它内部用了非常激进的并行算法和内存映射机制。同样,它默认尊重.gitignore,搜代码时不会把依赖目录里的海量文件也过一遍。一条rg "TODO|FIXME" src/就能瞬间列出所有的待办标记。fzf:模糊搜索选择器,这个工具非常有意思。它本身不查找任何东西,但可以接收任意文本流,让你在交互式列表中模糊搜索并选中一行,再把结果输出到stdout。比如kill -9 $(ps aux | fzf | awk '{print $2}')就可以实现“可视化选择进程并杀死”,这种交互感和精准度是纯命令搜索做不到的。jq:JSON数据的解析神器。现在几乎所有API都返回JSON,很多人调试的时候是复制到网页工具里再格式化。用jq可以直接在终端做格式化、过滤、提取字段。curl -s https://api.github.com/repos/some/repo | jq '.stargazers_count'一行命令拿到star数。
这四个工具配合起来的场景感很强:fd找到文件,rg搜索内容,jq解析结构化数据,fzf给人一个交互式选择入口。它们是整套CLI-Anything的地基。
2.2 网络请求与接口调试:curl、httpie
接口调试是前后端开发每天都要干的活。大部分人的习惯是打开Postman,然后配置请求头、请求体,来回切换窗口。说实话,对于简单接口,这完全是不必要的操作。
curl是终端的网络请求瑞士军刀,但它有个问题——参数复杂、输出原始。用curl调试JSON接口时,如果不配合管道里加jq,返回内容就是一坨没格式化的字符串。我在CLI-Anything里的标准姿势是这样的:
curl -s -X POST https://api.example.com/v1/users \ -H "Content-Type: application/json" \ -d '{"name":"zhang","age":30}' | jq这样一行命令就实现了发送请求、格式化输出、提取关键字段全流程。
如果你不太习惯curl的参数风格,可以用httpie这个替代品。它的语法更自然,http POST https://api.example.com/v1/users name=zhang age:=30就直接发送了JSON请求,默认彩色格式化输出。这些工具的价值不在于哪个比Postman强,而在于它们能把接口调用变成一行可复制的命令,写进脚本、写进文档、写进注释里都毫不违和。
2.3 容器与远程运维:docker、alias组合技巧
容器化之后,日常运维操作大量变成了docker命令的反复调用。我在实际项目里总结了一套CLI-Anything运维组合拳:
docker ps配--format自定义输出,只显示容器名、状态、端口映射。
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"进入容器诊断问题,别用
docker attach,它会把终端和容器主进程绑在一起,容易干扰业务。正确姿势是docker exec -it <container> sh。查看容器日志时,
docker logs -f --tail 100 <container>配合grep做过滤。比如只看ERROR级别:docker logs -f <container> | grep -i error。清理容器环境,一条
docker system prune -af可以干掉所有停止的容器、未使用的网络和悬空镜像。当然这个命令有破坏性,跑之前要确认环境。
远程运维方面,我习惯把常用服务器的SSH连接信息做成shell函数,而不是记住IP和密钥路径。比如:
function ssh-prod() { ssh -i ~/.ssh/prod_key user@10.0.0.1 "$@" }这样敲ssh-prod "uptime"就能直接执行远程命令。本质上,CLI-Anything在运维场景的核心思路是:把每次登录、每条排查命令都变成可重复执行的别名和函数,减少人脑记忆负担。
2.4 系统监控与资源排查:btop、ncdu、du
很多人在排查服务器问题时,习惯性地输入top,其实top的显示方式已经有些老了。我在CLI-Anything里首推btop,它是一个终端系统监视器,能直接画出CPU、内存、磁盘、网络的实时图表,而且显示非常清爽,一眼就能看出瓶颈在哪。
磁盘占用排查也是高频问题。ncdu是文本界面的磁盘分析工具,跑一遍ncdu /data就能以交互式树状图看哪个目录最占空间,然后进去逐个定位大文件。
另外,别忽略du命令本身的威力。du -h --max-depth=1 /data | sort -hr可以快速列出第一级目录的占用排序。这个组合命令不需要装任何工具,在绝大多数Linux机器上自带。
这组工具负责的是“发现问题”这一步。一旦从btop或ncdu里定位到异常,剩下的处理动作就用前面讲的kill、docker、systemctl之类的命令去执行。观察和行动都在终端内,全程不需要切换窗口。
3. 实操:从零搭建你自己的 CLI-Anything 工作流
3.1 第一层:增强Shell基础体验
整个CLI-Anything方案,底层依赖一个舒服的Shell环境。我的建议是,如果不满足于默认配置,先审视一下你用的是什么Shell。macOS默认是zsh,大多数Linux发行版默认是bash。我个人更偏向zsh,配合oh-my-zsh或者更轻量的框架来做基础增强。
但说实话,框架是次要的,关键是几个基础配置:
- 开启历史记录增强。让Shell记住更多的历史命令,并且支持模糊搜索。在zsh里设置
HISTSIZE=10000、SAVEHIST=10000,然后绑定Ctrl+R反向搜索历史命令。 - 配置自动补全。zsh原生的补全已经很好用,建议开启
autoload -Uz compinit && compinit,这样docker、git这些命令的子命令都能自动补全。 - 设置别名别名组。这是效率提升幅度很大的地方。以下是我常驻配置里的一部分,你可以直接抄过去:
# 替代默认命令 alias ls='ls --color=auto' alias ll='ls -lah' alias la='ls -A' # 安全操作习惯 alias cp='cp -i' alias mv='mv -i' alias rm='rm -I' # 简化快捷键 alias g='git' alias gs='git status' alias ga='git add' alias gc='git commit' alias gp='git push' alias gpl='git pull'加-i或-I参数让cp、mv、rm在覆盖或删除前进行交互确认,这个习惯能避免很多手滑事故。我见过不止一次因为把rm -rf顺手在错误目录执行而导致的悲剧,rm -I对包含大量文件的目录会要求额外确认,能起到缓冲作用。
3.2 第二层:用函数封装复杂操作
别名的能力有限,它只能简化静态命令。真正让CLI-Anything强大起来的是Shell函数,因为它可以接收参数、做逻辑判断、串联多个命令。
这里分享几个我日常使用频率极高的函数:
# mkdir并立即进入目录 mk() { mkdir -p "$1" && cd "$1" } # 查找文件并按修改时间排序 fcat() { fd -t f "$1" | xargs cat } # 快速压缩/解压,根据扩展名自动选择 compress() { if [ -d "$1" ]; then tar -czf "$1.tar.gz" "$1" elif [ -f "$1" ]; then case "$1" in *.tar.gz) tar -xzf "$1" ;; *.zip) unzip "$1" ;; *.rar) unrar x "$1" ;; *) echo "未知格式" ;; esac fi }Shell函数是CLI-Anything工作流的“业务逻辑层”。建议你复盘一下自己最近一周做过的高频操作,选3到5个动作封装成带参数的函数,这会是一套属于你自己的CLI工作流起点。
3.3 第三层:脚本化串联复杂工作流
函数解决单点操作,脚本则用来串联多步骤流程。举一个我实际项目里的例子:每次发布测试环境时,需要拉取最新代码、构建前端、重启后端服务、检查健康检查接口。这个流程有六七个步骤,过去是手动一步步敲,后来我把整条链写成了一个脚本deploy-test.sh:
#!/bin/bash set -e echo ">>> 拉取最新代码" git pull origin develop echo ">>> 构建前端" cd frontend && npm ci && npm run build && cd .. echo ">>> 重启后端服务" docker compose restart api echo ">>> 等待服务启动" sleep 5 echo ">>> 检查健康状态" curl -s http://localhost:8080/health | jq .注意这里面有几个关键设计:
第一,开头加上set -e,让脚本在任何一步失败时立即退出,避免后续命令在错误状态下继续执行。第二,每一步都有明确的提示语,出问题时能顺着日志定位。第三,最后一步带上健康检查,把结果直接输出出来,形成一个闭环。
类似的脚本你可以扩展出很多:数据库备份脚本、日志清理脚本、环境初始化脚本、依赖更新脚本。CLI-Anything的最终形态,就是这些脚本的集合——它把你的日常工作流程变成了一个随时可以重新执行的“程序”。
3.4 第四层:与编辑器和其他工具链配合
CLI工具链不是孤立存在的,它需要和日常编写代码的环境结合起来。我自己用的是Neovim,所以终端工作流和编辑器天然无缝。如果你是VS Code用户,完全可以用它内置的终端,把CLI-Anything的配置同步进去。
还有一个容易被忽略的配合点:终端快捷键设置。给终端设置一个全局热键,比如我用的是Ctrl+Shift+Space,在任何应用界面都能瞬间唤起一个浮窗终端。这样遇到要“快速执行一条命令”的场景,比如需要马上看一个JSON文件内容、查一个端口占用,不用再切换窗口,直接呼出终端敲完命令再关掉。
这种“全局即时终端”的思路,让CLI工具链变成了系统级的一种能力,不再是开发时打开的一个工具窗口。
4. 常见问题与排查技巧实录
4.1 中文乱码与编码问题
在CLI工作流中,中文乱码是一个非常高频的问题。核心原因有两种:一是文件本身的编码不是UTF-8,二是终端没有正确解析输出编码。排查思路很简单,先确认文件的编码格式,Linux可以用file命令查看:
file -i somefile.txt如果输出显示charset=iso-8859-1那就是非UTF-8编码,可以通过iconv -f gbk -t utf-8 somefile.txt > newfile.txt转换。另外在过滤日志时,一定记得在grep实例里加上--color=always或者确保终端的locale设置正确。我在实践中发现,很多时候不是命令的问题,而是SSH会话的locale没设好,执行export LANG=en_US.UTF-8就能解决。
4.2 GNU工具和BSD工具的兼容性坑
如果你在macOS上写好一套命令,上了Linux服务器发现行为不一致,这大概率是GNU版本和BSD版本的差异导致的。经典的例子是sed,Linux下的GNU sed用sed -i 's/a/b/g' file就可以原地替换,而macOS自带的BSD sed要求必须加一个备份后缀参数sed -i '.bak' 's/a/b/g' file,不然后果就是命令直接报错。
应对方案有两个:
一是安装GNU工具版本。macOS上用Homebrew运行brew install coreutils gnu-sed gnu-findutils,然后通过alias把它们映射到默认命令名上。
二是写脚本时避免依赖这些差异点,改用perl或者python脚本做复杂文本处理。
我个人的习惯是:日常交互式操作无所谓,但凡是会保存下来、或在线上的脚本,都要在两种机器上做过兼容性测试。这个经验来自一次线上事故——我当时写了一个配置清理脚本,只用macOS测过,推到Linux服务器上跑直接报错,好在影响范围不大,但从此以后我在脚本头部加了兼容性判断:
if [[ "$(uname)" == "Darwin" ]]; then # macOS 兼容分支 else # Linux 兼容分支 fi4.3 大量日志和超大文件时的性能陷阱
CLI工具在动辄几个GB的日志文件面前,也会有力不从心的时候。我踩过的一个典型坑是:使用cat huge.log | grep "error"来处理非常大的日志文件。这种方式会把整个文件先读入内存再过滤,文件一大,内存就被吃满了。
正确的做法是用grep直接读文件:grep "error" huge.log,它的内部实现是流式的,不会一次性加载全文件。另一个坑是过度使用sort处理超大文件,sort对大数据量本身就有很大的临时空间需求,如果/tmp分区不够,会出现sort: write failed的报错。
遇到几十GB级别的日志,我建议先用ls -lh确认大小,再决定是用tail先取尾部一段,还是用split拆分处理,而不是贪心想要一条命令解决全部。还有一些工具应付大文件效果很好,比如miller来处理CSV、xsv来做表格数据切片,这类工具本身对内存储使用做了更精细的管理。
4.4 学习曲线太陡,怎么渐进式上手
CLI-Anything这套体系工具众多,如果上来就想全盘掌握,很容易产生挫败感,最后放弃。
我自己的经验是先找痛点最强烈的一个点切入。假设你每天最烦的是在项目里找文件,那就先学一个fd,把它用熟了,建立信心,再学rg。不要试图一天之内把本文提到的所有工具都配齐。CLI能力的本质是复合增长,先掌握一个能明显提高效率的工具,这种成就感会驱动你继续学下一个。
另外一个比较实用的方法是“命令速查卡片”。在自己的配置仓库里放一个cheatsheet.md,把不常用的参数和用法记下来。我前几年养成的习惯是:每次解决一个命令相关的问题,就顺手往这个文件里追加一条笔记。日积月累,这比任何教程都更适合你自己的操作习惯。
回到CLI-Anything本身——它不是一个装完就结束的软件,而是一个慢慢生长的方案。你可以从本文抄几条别名开始,也可以直接照着函数和脚本的模板改,甚至可以把这套思路完全迁移到自己熟悉的工具上。我用了几年后的体会是,最重要的不是某条具体的命令,而是建立起“凡是重复皆可脚本化”的思维方式。遇到手工操作前先停几秒,想想能否写成命令,这个习惯一旦养成,你的效率曲线会比想象中提升得更快。