外观
AppleScript 与 JXA:驱动没有命令行接口的应用
很多 Mac 应用没有命令行接口,但支持被脚本控制——邮件、备忘录、访达、音乐、大部分办公软件都是。这套机制叫 Apple 事件,可以用 AppleScript 写,也可以用 JavaScript 写(后者叫 JXA,JavaScript for Automation)。
这一篇的核心不是语法,而是怎么查清某个应用到底支持什么。不会查,就只能到处抄别人的脚本,遇到版本变化无从下手。
开始之前
需要能在终端执行命令。本文的示例都是只读操作,不修改任何数据。
先理解一件事:能不能控制一个应用,完全取决于开发者有没有提供接口。Apple 自家应用支持得较好,第三方差异很大。抄来的脚本跑不通,第一件事是确认这个应用是否真的支持你要做的操作,而不是反复调语法。
先查脚本字典
每个支持脚本的应用都自带一份「脚本字典」,列出它能被控制的对象和操作。这是唯一可靠的依据。
打开方式:启动「脚本编辑器」(在「应用程序 → 实用工具」里,或用聚焦搜索),选「文件 → 打开词典」,从列表里选一个应用。
以「备忘录」为例,字典里能看到 note(便签)、folder(文件夹)这些对象,以及每个对象的属性,例如 name、body、creation date。脚本里能用的词就是这些,字典里没有的写了也不认。
应用不在列表里,说明它不支持脚本控制。这种情况下只能考虑辅助功能层面的模拟操作(例如用 Hammerspoon 发送按键),那是另一条路,可靠性低得多。
从终端执行
sh
osascript -e 'tell application "Finder" to get the name of the front window'osascript 是执行 AppleScript 和 JXA 的命令行工具。-e 表示后面跟的是要执行的脚本文本。tell application "..." to ... 是 AppleScript 的基本结构:告诉某个应用做某件事。
用单引号包住整段脚本,因为里面有双引号。访达没有打开窗口时这条命令会报错,这是预期行为。
写成多行脚本时存成 .applescript 文件再执行:
sh
osascript ~/bin/my-script.applescriptJXA:同样的能力,JavaScript 的语法
同一件事用 JXA 写:
sh
osascript -l JavaScript -e 'Application("Finder").windows[0].name()'-l JavaScript 指定语言,不加时默认是 AppleScript。
怎么选:熟悉 JavaScript 就用 JXA,否则用 AppleScript。两者能力相同,但网上的示例绝大多数是 AppleScript——遇到问题时能搜到的答案多得多。这个现实因素比语法偏好更重要。
JXA 的另一个问题是文档稀少,Apple 对它的更新也不积极。作为长期方案,AppleScript 目前更稳妥。
一个有用的例子
把当前浏览器标签页的标题和网址取出来,这是做笔记时的常见需求:
sh
osascript -e 'tell application "Safari" to get {name, URL} of current tab of front window'{name, URL} 表示同时取两个属性,返回一个列表。Safari 没有打开窗口时会报错。
换成 Chrome 时,词不一样:Chrome 的字典里用 active tab 而不是 current tab。这正是必须查字典的原因——同类应用的术语不通用。
自动化授权
第一次让 A 脚本控制 B 应用时,系统会弹出授权请求:「xxx 想要控制 xxx」。允许之后,授权记录在「系统设置 → 隐私与安全性 → 自动化」里,可以随时撤销。
有两点容易困惑:
授权是按「谁控制谁」这一对关系记录的。 终端控制访达、终端控制备忘录是两条独立授权。
从 launchd 运行时,请求者是实际执行的程序。 定时任务里执行 osascript,系统看到的请求者可能是 /bin/bash 或 osascript 本身,而不是你的脚本文件。所以后台任务第一次运行时可能因为没人点「允许」而静默失败——先在终端手工跑一次完成授权,再交给 launchd。
详细机制见TCC 隐私授权。
检查结果
三条命令验证环境正常:
sh
osascript -e 'return 1 + 1'
osascript -l JavaScript -e '1 + 1'
osascript -e 'tell application "System Events" to get name of every process whose background only is false'前两条应当都输出 2,证明两种语言都能执行。第三条列出当前所有非后台进程的名称,会触发一次自动化授权请求——允许之后再执行就不会再问。
「系统事件」(System Events)是个特殊的辅助应用,很多跨应用操作都要经过它。它出现在自动化授权列表里是正常的。
动手练习
用只读操作熟悉查字典的流程,不修改任何数据:
- 在脚本编辑器里打开「备忘录」的词典,找出
note对象有哪些属性。 - 写一条命令,取出备忘录中便签的数量。提示:
count of notes。 - 在「系统设置 → 隐私与安全性 → 自动化」里找到刚产生的授权记录。
- 关掉那条授权,再跑一次第 2 步,观察报错。
- 重新打开授权,确认恢复正常。
成功标准是第 4 步你看到的是授权被拒的错误,而不是语法错误——能区分这两类失败,排查效率会完全不同。全过程没有写入或删除任何便签。