外观
快捷指令与脚本互相调用
快捷指令擅长的是接入系统和应用的现成能力:读取剪贴板、处理照片、发通知、跨设备同步。Shell 脚本擅长的是文本处理、批量文件操作和调用命令行工具。
把两边接起来,你就不必在一侧硬撑。这一篇讲双向调用的方法,以及怎么划分职责。
开始之前
需要先会建立基本的快捷指令,见第十篇:自动化。需要能在终端执行命令。
在快捷指令里运行脚本
在快捷指令编辑器中搜索「运行 Shell 脚本」操作,拖进流程。几个要点:
输入怎么进来。 该操作可以接收上一步的输出。在「输入」下拉里选择作为标准输入传入,脚本里用 cat 读取;或者选择作为参数传入,脚本里用 $1 读取。两种方式行为不同,搞混会得到空值。
输出怎么出去。 脚本打印到标准输出的内容成为这一步的结果,可以接给下一个操作。所以调试时不要在脚本里乱 echo,多余的输出会一起传下去。
路径仍然是老问题。 和 launchd 一样,快捷指令运行脚本时的 PATH 与你终端里的不同。Homebrew 安装的命令要写绝对路径,例如 /opt/homebrew/bin/rg(Apple 芯片)或 /usr/local/bin/rg(Intel)。用 which 命令名 查出准确路径再填。
一个能立刻验证的例子——把输入的文本转成小写:
sh
cat | tr '[:upper:]' '[:lower:]'cat 读取标准输入,tr 做字符替换,两个参数分别是要替换的字符集和替换成的字符集。
从终端触发快捷指令
反方向用系统自带的 shortcuts 命令。
列出全部快捷指令:
sh
shortcuts list运行其中一个:
sh
shortcuts run "快捷指令的名称"名称含空格或中文时要加引号。传入内容:
sh
echo "要处理的文本" | shortcuts run "我的快捷指令"管道符 | 把左边命令的输出送给右边作为输入。需要把结果拿回来时加 --output-path:
sh
shortcuts run "我的快捷指令" --output-path /tmp/result.txt--output-path 指定把快捷指令的输出写到哪个文件。用 - 作为路径值表示写到标准输出。
职责怎么分
不要把所有逻辑都堆在一侧。经验规则:
| 交给快捷指令 | 交给脚本 |
|---|---|
| 读写照片、通讯录、日历、提醒事项 | 文本解析与格式转换 |
| 发系统通知、弹出选择菜单 | 批量重命名、按规则整理文件 |
| 接入分享菜单、触发式自动化 | 调用命令行工具(ffmpeg、rg、Git) |
| 在 iPhone、iPad 上也要能用 | 需要循环、条件和错误处理的逻辑 |
最后一行值得展开:快捷指令能在 iPhone 上运行,Shell 脚本不能。需要跨设备的流程,逻辑尽量留在快捷指令一侧;只在 Mac 上跑的流程,复杂逻辑放脚本里可读性好得多。
快捷指令的循环和条件判断在流程稍长之后会变得很难读——一屏放不下、无法用版本库比较差异。超过十来步就该考虑把核心逻辑挪进脚本,快捷指令只负责取输入、给输出。
让它自己跑起来
两条路径:
- 快捷指令自身的自动化:在快捷指令 App 的「自动化」里按时间、连接充电器、连上某个 Wi-Fi 等条件触发。适合与设备状态相关的任务。
- 交给 launchd:写一个 LaunchAgent 执行
shortcuts run,见用 launchd 让任务按时间和事件运行。适合需要精确调度、需要日志和退出码的任务。
选后者时注意,快捷指令若涉及照片、文稿等受保护数据,后台首次运行会因为没有人点「允许」而失败。先在终端手工跑一次完成授权。
检查结果
sh
shortcuts list | head能列出你的快捷指令,说明命令行工具正常。
然后建一个只有一步「运行 Shell 脚本」的快捷指令,脚本内容填 date,命名为「测试时间」,再从终端执行:
sh
shortcuts run "测试时间" --output-path -应当输出当前时间。--output-path - 把结果打到终端。这条链路通了,说明双向调用都可用。
动手练习
做一个两侧协作的小流程:
- 新建快捷指令「转小写」,只含一步「运行 Shell 脚本」,内容为
cat | tr '[:upper:]' '[:lower:]',输入设为标准输入。 - 在快捷指令 App 里点运行,用剪贴板内容测试。
- 从终端执行
echo "HELLO World" | shortcuts run "转小写" --output-path -。 - 故意把脚本里的
tr改成/nonexistent/tr,再跑一次,观察失败表现。 - 改回来确认恢复。
成功标准是第 3 步和第 2 步得到相同结果——同一个快捷指令,两种触发方式行为一致。第 4 步的意义是先见识一次失败的样子:快捷指令的报错信息通常比终端简略得多,这是把复杂逻辑放脚本里的另一个理由。