☰
CLI-Anything:用命令行把重复工作变成可复用脚本
2026/9/28 17:14:53 网站建设 项目流程

命令行这个东西,一旦用顺了,就真的回不去了。CLI-Anything 这个名字听起来很像某个开源项目的代号,但在我眼里,它更像一套思路:把所有值得重复做的事,都收敛成一条能在终端里敲下去的命令。不管是批量改文件名、把一堆散落的日志汇总成表格,还是每天固定拉取几个接口的数据存成存档,只要这个动作你做过三次以上,就值得把它变成 CLI 的一部分。这篇文章想分享的就是这套方法——不依赖某个特定框架,不要求你会复杂的编程,只需要一点点 Shell 基础,就能搭出一个属于自己的“万物可命令行”工作台。

我会从命名拆解开始,逐步讲到基础设施搭建、三个高价值场景的完整落地,再补充进阶技巧和排错心得。全程用真实命令和实际场景说话,适合开发者、运维、数据分析师,也包括所有整天泡在电脑前处理琐碎事务的效率控。内容比较长,建议先收藏,然后打开终端跟着敲一遍。

1. CLI-Anything 到底是什么:从命名拆解设计思路

1.1 拆开名字看本质:CLI 是入口,Anything 是边界

CLI-Anything 这个词组可以拆成两半来看。前半部分 CLI 指的是 Command-Line Interface,也就是命令行界面。后半部分 Anything 是“任何东西”,但这里的任何东西绝不是指“在终端里打游戏、刷视频”这种娱乐向操作,而是指所有具备以下特征的日常事务:重复执行、有明确输入、有可预期的输出、结果需要留下记录。

举个例子,你每周五下午都要把某个目录里的周报文件按日期重命名、压缩、丢到备份目录。第一次做可能是手工操作,第二次开始你就觉得烦,第三次就应该写一条命令了。这条命令就是“Anything”的一个切片。CLI-Anything 的核心思路,并不是要你去学一个庞大无比的工具框架,而是建立一种肌肉记忆:遇到重复操作,第一反应是“我能不能把它变成一条命令”。

这个思路最大的价值在于,它把“一次性手工劳动”转化成了“可积累的资产”。命令本身是纯文本,可以被保存、被修改、被复用,也能被分享给同事。你今天写的这条小脚本,三个月后可能就长成了一个小工具箱。

1.2 为什么偏偏是命令行:三个无法替代的优点

图形界面当然有它的优势,但落到“重复事务自动化”这个场景里,命令行有三个图形界面很难替代的优点。

第一,可组合性。命令行工具天然遵循“输入输出皆为文本”的约定,你可以用管道把一个命令的输出接到另一个命令的输入。比如ls | grep log | wc -l这一条,就完成了“列出文件、筛选带log的、统计数量”三个步骤。图形界面里的多数操作是无法像这样串联的,你只能在界面里一步步手动点。第二,可追溯性。命令敲下去之后,终端历史记录、脚本文件本身,就是完整的过程记录。你要是想复盘“上周的那批数据是怎么处理的”,翻开历史记录或者脚本目录就能一目了然,而不是心里揣测当时到底点了什么按钮。第三,稳定复现。脚本跑一百次,结果是稳定一致的,不受鼠标位置和界面状态影响。这一点对数据处理、批量操作、定时任务来说,几乎是刚需。

1.3 谁适合这套思路:边界和门槛先讲清楚

先说门槛。你不需要成为 Shell 专家,也不需要会 Python 后端的那些花活。只要你能理解变量、循环、条件判断,并且愿意照着文档敲命令,就已经足够了。真正的门槛只有一个:你有没有“遇到重复操作就想着脚本化”的意识。

再说边界。CLI-Anything 不适合解决所有问题,比如复杂的图像编辑、需要精细排版的设计稿、需要鼠标交互的桌面操作,这些场景强行命令行化反而会降低效率。我自己的经验是,它最适合的三类事情分别是:纯文本与文件的批处理、数据抓取与格式转换、以及定时执行的巡检任务。明白边界之后,往下搭建就不容易走偏。

2. 搭建基础设施:先把自己常用的命令目录收拾干净

2.1 终端与 Shell 的选择:一只好用的“手”是效率基础

CLI-Anything 这套思路不依赖某个特定终端,但一只好用的“手”能明显提升体验。如果你用的是 Linux 服务器或者 macOS,系统自带的终端已经够用;Windows 用户建议装一个 Windows Terminal,把默认 Shell 切到 PowerShell 或者 WSL 里的 Bash。我个人长期用 Zsh 配合 Oh My Zsh,主要图它补全体验好、历史记录强大,而且主题让命令和输出层次分明。不过这只是锦上添花,底层逻辑都一样——你需要在终端里舒舒服服地敲命令、跑脚本、看输出。

Shell 的选择上,如果你是零基础起步,先学 Bash 是对的。它是几乎所有 Linux 发行版默认带的 Shell,资料最多、兼容性最好,你写的脚本拿到任何一台服务器上基本都能跑。Zsh 和 Bash 在语法上高度兼容,从 Bash 起步再去用 Zsh,几乎不会有什么障碍。

2.2 脚本目录与 PATH 设计:让每条命令随时可调用

很多人的脚本写得没问题,但苦于调用不方便,每次都要bash /home/user/scripts/xxx.sh这样一长串。其实解决办法很简单:把所有脚本放进同一个目录,然后把这个目录加到 PATH 里。

以 Linux/macOS 为例,我习惯用~/.local/bin作为个人脚本目录。在.bashrc或.zshrc里加上这样一行:

export PATH="$HOME/.local/bin:$PATH"

加完之后执行source ~/.bashrc,再把脚本文件放到~/.local/bin下,同时给脚本加上执行权限:

chmod +x ~/.local/bin/mycmd

之后你就可以在任意目录直接敲mycmd来执行它,不需要再带路径,也不需要再打bash前缀。这一步是整个 CLI-Anything 体验的关键。一旦你的命令可以从任何目录被调起来,它才真正拥有了“系统命令”的体感。

2.3 脚本语言怎么选:别一上来就纠结

在选脚本语言这件事上,我见过太多人犯选择困难症。其实你可以遵循一条简单的原则:逻辑简单、以调用外部命令为主的操作,用 Bash;逻辑复杂、涉及数据处理和字符串解析的,用 Python。

Bash 的优势在于胶水能力强,能轻松调用tar、curl、jq这些外部程序,写个文件批处理脚本只需要十几行。它的弱点是语法比较古老,数组、字符串处理、浮点运算都非常别扭。Python 则胜在表达力强、库丰富,适合写稍微复杂的逻辑。我个人的做法是,目录里的脚本基本是 Bash 为主,碰到 JSON 解析、表格计算这类需求,再转去写 Python。两种语言在同一个~/.local/bin目录下可以和谐共存,命令行会自动根据 shebang 选择解释器。

如果你对 dotfiles 版本的配置管理有兴趣,还可以把这个目录整个纳入 Git 仓库,换新机器时一条git clone加一个软链接就能恢复全部命令。这属于进阶玩法,但确实能让你更安心地把命令积累下去。

3. 三个高价值场景的完整落地:从命令到工作流

3.1 场景一:批量文件处理的完整命令

先讲一个我自己几乎每周都会用到的场景:批量重命名。假设手机照片导出来后,所有文件都是IMG_20240101_123456.jpg这样的命名,你想把它们统一改成photo-日期-序号.jpg的格式。手改肯定不现实,脚本只需要五行:

#!/usr/bin/env bash i=1 for f in IMG_*.jpg; do mv "$f" "photo-$(date +%Y%m%d)-${i}.jpg" i=$((i + 1)) done

这里有几个细节值得解释。第一,for f in IMG_*.jpg里的通配符会在执行前被展开成真实文件名列表,所以脚本能正确处理带空格的文件名,前提是后面引用时一定要加引号。第二,$(date +%Y%m%d)是命令替换,在执行时得到当天的日期字符串,这样每天跑出来的新文件名都自动带上当天日期。第三,i=$((i + 1))是 Bash 的算术语法,单纯用i=$i+1是得不到自增效果的,这是新手很容易踩的坑。

批量压缩备份是另一个典型场景。把某个目录打包成带日期后缀的归档文件:

#!/usr/bin/env bash backup_dir="${1:-./backup}" tar -czf "backup-$(date +%Y%m%d-%H%M%S).tar.gz" "$backup_dir"

${1:-./backup}的意思是:如果调用脚本时传了第一个参数,就用这个参数;否则用默认值./backup。这种写法让脚本既能在传参时灵活指定目录,又能在不传参时默认工作,属于我非常推荐的一个小技巧。如果还想进一步压缩图片体积,配合 ImageMagick 的convert命令能一条循环搞定:

for f in *.png; do convert "$f" -resize 1920x1080 -quality 80 "${f%.png}-compressed.jpg" done

${f%.png}是参数扩展,表示把变量f末尾的.png去掉,这样就能生成以-compressed.jpg结尾的新文件,而不会覆盖原图。这些语法听起来复杂,用多了就会发现它们是同一套规律的变体。

3.2 场景二:用文本文件记账,再用 awk 自动汇总

记账是我觉得 CLI-Anything 最能体现“轻量高效”的场景。市面上记账 App 非常多,但它们的数据大多困在某个生态里,想导出、想自定义统计都很麻烦。我的做法极其原始:一个纯文本 TSV 文件,一行一条流水,格式固定为日期、类别、金额、备注。

2024-12-01 餐饮 32.50 午饭 2024-12-02 交通 6.00 地铁 2024-12-02 购物 129.90 耳机

记录的时候直接在终端里追加一行:

echo -e "2024-12-03\t餐饮\t48.00\t晚饭" >> ~/finance/2024-12.tsv

可能有人觉得这不比 App 麻烦多了?但如果我把“记录”也变成一条命令呢?比如在~/.local/bin里写一个addexp脚本:

#!/usr/bin/env bash date_str=$(date +%F) echo -e "${date_str}\t$1\t$2\t$3" >> "$HOME/finance/$(date +%Y-%m).tsv"

之后每次消费完,终端里敲addexp 餐饮 32.5 午饭就完成记录了。刚开始你可能觉得多敲几个字符无所谓,但只要坚持两周,终端记一笔的速度绝对比打开 App 点三四个页面快得多。

真正体现命令行威力的是汇总统计。想算这个月餐饮一共花了多少?一个 awk 就够:

awk -F'\t' '$2 == "餐饮" {sum += $3} END {printf "本月餐饮支出: %.2f\n", sum}' ~/finance/$(date +%Y-%m).tsv

解释一下这个命令。-F'\t'指定字段分隔符是制表符;$2 == "餐饮"是条件过滤器,只处理第二列等于“餐饮”的行;sum += $3把第三列的金额累加起来;最后在 END 块里用printf格式化输出两位小数。整个逻辑不需要写循环,awk 自己会逐行读文件,两行代码搞定了传统编程语言里至少十行的逻辑。

如果你想把按月汇总做成一条永远可用的命令,也可以把它升级成脚本monthly-summary,支持传入月份参数,还顺带计算总支出、最高单笔消费这些统计。这就是从“一条命令”走向“一个工具”的过程。

3.3 场景三:把自己常用的 API 封装成一条命令

第三个场景跟 Web 开发关系比较大:经常需要查接口数据。比如你想快速查某个城市的天气,传统的做法是打开浏览器、输入天气网站、看页面。用 CLI-Anything 的思路,就变成了调用公共天气接口再用 jq 解析 JSON,全程两秒钟。

jq 是命令行下处理 JSON 的事实标准工具,必装。以查询天气为例,可以这样写:

#!/usr/bin/env bash city="${1:-北京}" curl -s "https://wttr.in/${city}?format=j1" | jq '.current_condition[0] | {temp: .temp_C, humidity: .humidity, desc: .weatherDesc[0].value}'

curl -s表示静默请求,不显示进度条。jq 的管道语法.current_condition[0] | {...}表示先取出数组第一个元素,再从中选取温度、湿度和天气描述字段,最后输出成 JSON。效果是终端里干净利落地显示三行数据,适合写进定时脚本做早上播报。

类似思路也适用于查汇率、查快递、查服务器状态这类场景。关键点在于:接口返回的 JSON 数据不要裸着看,一定要用 jq 做字段抽取。裸看 JSON 在数据量大时完全是灾难,而 jq 能把任意结构化成你想要的摘要。

如果你要交互的接口还需要带鉴权头,也可以把 token 写进脚本的环境变量文件里,或者用curl -H "Authorization: Bearer $TOKEN"的方式管理。不建议把密钥硬编码进脚本正文,更不建议提交到 Git 仓库,这是个安全底线。

4. 进阶玩法:让命令更健壮、更自动化

4.1 参数、默认值和交互输入:命令也开始“听懂人话”

当脚本数量变多,你会自然希望它们能“听懂”人话——接受不同参数,有合理的默认值,必要时候还能提醒你漏了什么。实现这一点不需要什么框架,掌握几个小技巧就够。

位置参数的玩法我在前面已经提到过:$1是第一个参数,$2是第二个。给参数设默认值的惯用法是${1:-默认值}。如果你希望某个参数必填,缺失时报错退出,可以用:

if [ -z "$1" ]; then echo "用法: mycmd <必填参数> [可选参数]" exit 1 fi

-z表示检查字符串是否为空。这种写法让脚本在误调用时能给出友好提示,而不是闷头跑完发现结果不对。

需要交互确认的场景,直接用read命令。比如批量删除前先确认一次:

read -r -p "确定要删除这 ${count} 个文件吗?(y/N) " answer if [[ "$answer" != "y" && "$answer" != "Y" ]]; then exit 0 fi

-r防止反斜杠被转义,-p用来显示提示文本。加上这个确认步骤之后,你再也不用担心手滑跑错批量清理脚本。

4.2 错误处理与退出码:脚本要“大声失败”

新手写脚本最常见的问题是:命令失败时脚本继续往下跑,最后得到一个莫名其妙的结果。原因在于 Shell 默认不检查每条命令的退出状态,只有你主动声明,它才会敏感起来。

推荐一套我用了很久的脚本头组合:

#!/usr/bin/env bash set -euo pipefail

这串代码包含了三层意思。set -e表示一旦任何命令返回非零退出码,脚本立即终止;set -u表示使用未定义变量时直接报错,能帮你抓出大量拼写错误;set -o pipefail表示在管道中,只要有一环命令失败,整个管道的退出状态就是失败。这三者合在一起,让脚本从“闷声闯祸”变成“大声失败”,逼着你尽早发现问题。

如果你还想在脚本异常退出时留下现场信息,可以用trap:

trap 'echo "脚本在第 $LINENO 行出错,退出码: $?" >&2' ERR

$LINENO是 Bash 的内置变量,记录当前行号;>&2表示把错误信息输出到标准错误流,跟正常输出区分开。这样脚本出问题时,你能直接看到是第几行挂了,修复起来快得多。

4.3 定时任务与日常巡检:让命令替你值夜班

CLI-Anything 真正最有价值的地方,在于它和 cron 结合后能实现无人值守。比如你有一台服务器,想每天凌晨 2 点备份数据库、每周五下午 5 点生成周报、每小时检查一遍关键端口是否存活。这些都可以用简单的 crontab 搞定。

0 2 * * * /home/user/.local/bin/backup-db >> /home/user/logs/backup.log 2>&1 0 17 * * 5 /home/user/.local/bin/weekly-report

crontab 的五段格式分别是分、时、日、月、周。第一条表示每天 02:00 执行备份脚本,输出追加写入日志;第二条表示每周五 17:00 生成周报。2>&1的作用是把标准错误也重定向到同一个日志文件,避免报错信息丢失在终端历史之外。

我自己习惯把所有输出都留痕,因为定时任务不像手工执行那样能实时盯控制台。每次跑完看一眼日志,比事后猜问题靠谱得多。如果某条任务要求失败时立刻提醒你,还可以在脚本里加上调用通知接口的逻辑。别小看这一步,它把“定时任务”升级成了“自动巡检值班员”。

5. 常见问题与排错实录:踩过的坑都写在这里

5.1 命令找不到、没有权限、中文乱码:先排查这三个

命令行工具用久了,几乎人人都会碰到几个极经典的报错。第一个是command not found。原因基本逃不过三种:脚本没有放进 PATH 目录、脚本缺少执行权限、或者你在脚本头部忘了写 shebang(比如#!/usr/bin/env bash)。检查顺序就按这三条来,基本能定位八成问题。

第二个是Permission denied。在 Linux/macOS 下,这个报错说明文件没有执行权限,运行chmod +x 文件名即可。第三个是中文乱码。脚本里有中文,在服务器上跑成一堆乱码,大概率是系统的 locale 没有设置 UTF-8。可以在脚本开头显式指定:

export LANG=zh_CN.UTF-8

或者更稳妥一点,用export LC_ALL=C.UTF-8。这个问题的坑在于,本地 Mac 终端跑得好好的,服务器上一跑就乱,根源不在脚本而在环境变量。遇到乱码先查 locale,而不是怀疑代码写错了。

5.2 调试三板斧:从“盲跑”到“看清每一步”

写命令行脚本最怕的就是“盲跑”——脚本执行完,只知道结果不对,但完全不知道中间哪一步出了偏差。我调试 Shell 脚本的固定三板斧如下。

第一板斧是bash -x。给脚本执行时加上-x参数,比如bash -x myscript.sh,Shell 会把每一行命令展开后的真实执行过程打印出来,包括变量的展开值。这对排查“变量为什么是空的”“参数为什么传错了”非常直观。第二板斧是在关键位置插入echo调试输出。如果你不想一跑就满屏日志,可以先在可疑的位置打一个带标识的 echo,比如echo "DEBUG: 当前文件是 $f"。第三板斧是安装并使用 ShellCheck。它是一个静态检查工具,能直接指出来很多 Bugs,比如变量忘加引号、管道写错、语法不符合 POSIX 规范等。Linux 下可以apt install shellcheck,macOS 下brew install shellcheck。这个工具我强烈建议所有写 Bash 的人装一个,它比任何插件都更能提升脚本质量。

5.3 常见问题速查表:一点对应的排查手册

为了方便你直接对照排查,我把上述问题整理成一张速查表。这张表本身也符合 CLI-Anything 的思路——把零散的经验收敛成可查阅的清单。

现象常见原因解决方法
command not found脚本目录不在 PATH 中检查echo $PATH,添加路径
command not found脚本缺少 shebang在首行加#!/usr/bin/env bash
Permission denied没有执行权限chmod +x 文件名
中文输出乱码locale 未设置 UTF-8export LC_ALL=C.UTF-8
管道没有输出上游命令失败但未被发现加set -o pipefail
脚本总在同一个位置报错变量展开值不符合预期用bash -x查看展开过程
脚本在 Windows 下编辑后无法运行换行符是 CRLFsed -i 's/\r$//' 文件名

最后一行值得单独多说一句。很多人写脚本时习惯了 Windows 的换行符,传到 Linux 服务器上会多出一个不可见的\r字符,导致脚本运行时出现各种诡异问题。解决方式就是这条 sed 替换,把行尾的\r删掉。遇到过的人都知道这个坑有多莫名其妙,没遇到过的记住了能省两小时排查时间。

结尾:从一条命令开始,慢慢建起自己的工具箱

写了这么多,我最想强调的一点其实是心态。CLI-Anything 不是某个需要一次性安装部署的庞然大物,而是一个持续积累的过程。你可以从下周一开始,把第一个重复操作写成脚本,放进~/.local/bin,然后慢慢地,它会变成两个、十个、几十个。真正让你的终端变得强大的,从来不是某个特定的工具,而是“凡重复三次必脚本化”这个习惯本身。

我个人这几年的体会是,命令行效率的巅峰不在于敲命令的速度,而在于你手里攒下多少条经过反复打磨、已经稳定工作了好几个月的命令。它们就像你请来的员工,每天固定巡回、默默干活、还从不请假。搭建 CLI-Anything 的过程,本质上就是给自己培养一支这样的“数字劳动力”。工具选型的区别、语言偏好的争执,在这些已经跑起来的工作流面前,其实都不重要了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询