让计算机执行任务
摘要
作者回顾了学习shell脚本以自动化任务和集成程序的过程,强调了从基本命令到更复杂逻辑的转变,从而提高开发效率。
暂无内容
查看缓存全文
缓存时间: 2026/09/20 09:31
# 指挥电脑执行任务
来源:https://will-keleher.com/posts/telling-your-computer-to-do-things/
在我职业生涯的头几年,我并不知道如何指挥电脑完成任务。我只能从终端运行一些简单的命令——执行测试、安装依赖、启动容器、通过ssh连接服务器——但我仅限于逐条执行这些指令。那时我的终端堪称世界上最糟糕的图形界面,我误以为Shell就是用来启动那些没有图形化包装程序的工具。
从根本上说,我当时无法让电脑完成任何需要逻辑判断或整合多个程序的工作,例如:
- 先完成A任务再执行B任务
- 若命令失败则输出错误信息
- 电脑启动时自动运行某程序
- 同时执行两个命令
- 遍历目录中所有文件并逐个处理
- 将某个命令的输出作为另一个命令的输入
理论上我本可以用NodeJS编写这类程序,但实际上我从未尝试过。部分原因是思维定式:我不习惯将命令行程序视为可被我掌控的对象。更关键的是技能欠缺:我对这些程序的了解不足以将其整合到自己编写的脚本中。
但我持续学习Shell,逐渐能看懂这类包含基础逻辑的脚本:
```
set +e
npm install
status_code=$?
if [[ "$status_code" != "0" ]]; then
echo "npm安装出错。请检查~/.npmrc文件确保已认证官方仓库。"
exit 1
fi
set -e
```
如果你不熟悉Shell脚本,此刻可能已经看得眼花缭乱。抱歉(如果现在还没被这些符号刺痛眼睛,稍后你会明白为何应该关注:1 (https://will-keleher.com/posts/telling-your-computer-to-do-things/#fn:1))。
尽管我写的命令和脚本存在种种问题,但对我而言这是颠覆性的突破——我突然能够指挥电脑将现有程序组合起来实现目标。这种感觉类似于当初学会编程时的蜕变。
经过多年积累,我逐渐掌握更多Shell工具和语法。每当学到新工具或模式时,总会懊恼地意识到:若早知有此妙招,过去那些问题本可用更优雅的方式解决。
在此期间,我与许多(极其优秀的!)工程师共事,他们未花太多时间钻研Shell,而是依赖图形界面完成测试运行、Git管理、数据库操作等日常任务。依赖图形界面本无问题,但当需求超出界面预设功能时,就容易陷入思维局限——我曾目睹技术娴熟的工程师因不知如何用`while`循环重复执行命令,或用`for`循环批量处理文件而耗费大量精力。
我认为这种界面依赖思维在Shell脚本的编写与维护中同样存在隐患。多数公司的构建、部署、验证流程都依赖Bash/Zsh等语言编写的核心脚本。若对工具链所用的语言不熟悉,就无法轻松阅读或改进这些脚本。这就好比你能指挥远程服务器运行代码,却无法让本机电脑并行执行代码检查和测试——多么遗憾!
容我暂时偏离主题:为何如此多脚本不用团队主流语言编写?我认为用专为命令整合设计的语言编写脚本更符合人体工学。以运行测试直到失败为例:`while pnpm exec mocha ./pathToFile.test.ts; do true; done`。虽然这语法存在明显可改进之处,但看看NodeJS版本:
```
const { execSync } = require("child_process");
while (true) {
try {
execSync(`pnpm exec mocha ./pathToFile.test.ts`, { stdio: "inherit" });
} catch (err) {
console.error("failed", err);
break;
}
}
```
这段代码存在诸多冗余细节,我个人仍觉得Shell更简洁!不必创建文件、引入`child_process`模块,也不用设置`{ stdio: "inherit" }`来查看输出。而这只是个未使用管道、未捕获输出、未使用临时文件的简单示例!
💡
这并不意味着你必须局限于Bash/Zsh等类似语言!对于熟悉JavaScript的团队,我推荐使用zx (https://github.com/google/zx)。它能显著提升脚本的编写与维护体验。Ruby和Python同样比NodeJS更便捷,但确实存在某些语言编写此类脚本时需要更多仪式性代码。
我绝非主张Shell脚本永远最适合构建任务!当需求简单到只需连接两个程序时,Bash或Zsh显得相当顺手。但当需要更复杂的逻辑和数据类型时,就该选择能轻松表示(并测试!)这些特性的语言。
我推测许多抱怨构建脚本使用Shell语言的工程师,实际并未尝试将其转换为其他语言。除了语法可能更复杂外,“学习编写Shell脚本”的很大一部分其实与语法无关。如果你只是将命令组合起来,却不清楚这些命令的协同行为,最终脚本很可能同样难以理解。
精通Shell——即能够指挥电脑完成任务——很大程度上依赖于对目标程序的掌握程度!我认为Shell知识中语法占20%,工具箱储备占80%:
- 掌握`fzf`可构建快速模糊搜索工具(例如:`git checkout $(git branch --sort=-committerdate | fzf)`实现分支模糊选择)
- 熟悉`tldr`或`eg`可随时查询其他命令的用法示例
- 会用`rsync`可将变更文件同步至高速远程服务器执行重型任务
- 掌握`xargs`可增量构建命令并实现工作并行化
- 了解`sed -i`或`ast-grep`可快速批量修改文件中的复杂模式
- 使用`direnv`可确保代码库所有命令运行时环境变量正确
- 运用`duckdb`可在脚本中通过SQL查询本地CSV/JSON文件
- 通过`gh`可构建PR检查和创建工具
- 借助`ngrok`可快速暴露本地端口供其他机器测试
每掌握一个新程序都能指数级扩展你的能力,因为新工具能与所有已知工具协同作用。
我必须强调自己离Shell脚本专家相去甚远,与真正精通者相比仍有巨大差距2 (https://will-keleher.com/posts/telling-your-computer-to-do-things/#fn:2),但通过掌握足够的Shell语法来组合程序,并熟悉那些值得整合的工具,我已获益匪浅。
指挥电脑执行任务确实非常美妙!
相似文章
@_philschmid: 另一个苦涩教训即将到来。你可能已经注意到,你的编码代理越来越倾向于使用bash而不是专用工具……
这篇文章讨论了AI编码代理如何越来越倾向于使用bash脚本而不是专用工具,并且对此变得非常熟练,这可能导致AI开发中的另一个'苦涩教训'。
@mvanhorn: https://x.com/mvanhorn/status/2063865685558903149
本文解释了AI编程中'循环'的概念,即开发者编写程序来提示编码代理,而不是手动提示,这一概念由Peter Steinberger和Boris Cherny推广开来,并讨论了这种转变如何代表了AI辅助开发中的新抽象层。
@omarsar0: https://x.com/omarsar0/status/2068008743153832264
这篇文章解释了从手动提示编码助手到设计自动循环来提示它们的转变,详细说明了这些循环是什么、它们的历史演变以及在生产中构建它们所需的组件。
我觉得人们严重低估了现在用AI自动化PC有多简单。
这篇文章指出,AI现在让非程序员也能通过自然语言描述需求,极其轻松地自动化电脑任务,如日程安排、浏览器控制和文件管理。
关于人工智能
作者回顾了自己从在老旧Macintosh上手动输入代码到使用Copilot和Claude等AI辅助代码补全工具的历程,并得出结论:尽管AI行业存在问题,但技术本身是有用的。