AppleScript

AppleScript 虽然是一种脚本语言,但在我看来是最接近天然语言和最不具有计算机特质的编程语言了。即便没有计算机基础,在阅读基础文档和几个样例脚本以后,立刻就能动手写出实用的脚本工具。ios

我感受不少使用 Mac 系统的同窗可能都没意识到,与本身天天做伴的 Mac 系统上还有这么一个强大高效的脚本语言,能够从各个方面提高本身的工做效率。接下来的文章和你们分享我使用 AppleScript 的两个场景。shell

在开始以前,先简单归纳下 AppleScript 的应用环境。咱们的 Mac 系统从应用的角度来看,其实就是一堆 App 的集合,系统自带的 App(Mail,Safari,Terminal 等)和安装的第三方 App(Firefox,Chrome,Outlook,iTerm 等),这些主流的 App 其实都向系统暴露了一些实用接口,用来将一些高频操做自动化。谁来调用这些接口呢?AppleScript。AppleScript 能够将这些 App 和 App 内部的数据,都看成对象来访问,甚至能够将不一样 App 串联,自动化以后造成一个 workflow。编程

如何编写 AppleScript 呢?Mac 自带脚本编辑和运行工具,经过 Spotlight Search 搜索 Script Editor 便可。运行 Script Editor 以后,经过菜单 File -> Open Dictionary 便可打开以下图所示一个文档,里面列出来全部支持 AppleScript 的 App,以及各个 App 所支持的接口调用。数组

 

applescript00.pngxcode

提高工做效率,避免重复劳动浏览器

我最近在研究如何下降 App 的 Crash 率,天天都要实时监控是否有新的 crash 发生。全部可能严重的 crash 警报都经过邮件发送到我邮箱,一旦收到警报我须要将邮件中的 crash id 复制出来,去另外一个网页工具里查询。天天早上看着一大堆警报,若是要将全部的 crash id 手动复制出来,一个个贴入网页里查询,操做很繁琐。AppleScript 能够轻松将这个流程自动化,一键搞定。步骤以下:app

邮件分类编程语言

邮件都是保存在 Microsoft Outlook 中,我首先设置一个 rule,将全部邮件标题包含 Trending Crash:xxx 字样的邮件都存入一个子文件夹:iOS-Crash。工具

遍历邮件url

再经过 AppleScript 遍历 iOS-Crash 目录下全部文件:

1
2
3
4
5
tell application  "Microsoft Outlook"
     set  theMessages to messages of folder  "iOS-Crash"  of  default  account
     repeat  with  theMessage  in  theMessages
     end repeat
end tell

上面这段脚本读起来是否是一目了然?就像是在和 siri 聊天同样,告诉 siri 遍历某个目录下的所有邮件。

提取 Crash ID

AppleScript 的另外一个强大之处是能够和系统自带的各种经常使用命令行工具(好比 grep,sed,awk 等)交互,这意味着对文本和文件的操做能够游刃有余。接下来我要经过 sed 工具来提取邮件中的 Crash ID:

1
2
3
4
5
6
7
8
9
10
11
tell application  "Microsoft Outlook"
     set  theMessages to messages of folder  "iOS-Crash"  of  default  account
     set  crash_id_set to {}
     repeat  with  theMessage  in  theMessages
         set  msgContent to plain text content of theMessage
         tell me to  set  crash_id to  do  shell script  "echo "  & quoted form of msgContent &  " | sed -E -n 's_.* crash_id:(.+)}_\\1_1p'"
         if  crash_id  is  not  in  crash_id_set and the length of crash_id >  0  then
             set  crash_id_set to crash_id_set & crash_id
         end  if
     end repeat
end tell

关键代码是这一行:

1
tell me to  set  crash_id to  do  shell script  "echo "  & quoted form of msgContent &  " | sed -E -n 's_.* crash_id:(.+)}_\\1_1p'"

AppleScript 用 tell xxx 的方式来切换脚步运行环境,好比

1
tell application  "Microsoft Outlook"

是切换到 Outlook 的进程中。

1
tell me to

是切换到当前用户的运行环境,由于咱们要执行命令行脚步,须要更高级权限,因此要切换到当前用户进程。

接下来经过 echo 将邮件的内容传递给 sed,并提取出 crash-id,将值传回 AppleScript 中的便利 crash_id,放入数组中。

拼装 url 并在浏览器中打开

这是最后一步,将上面提取结果在浏览器中打开:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
tell application  "Microsoft Outlook"
     set  theMessages to messages of folder  "iOS-Crash"  of  default  account
     set  crash_id_set to {}
     set  param to  ""
     repeat  with  theMessage  in  theMessages
         set  msgContent to plain text content of theMessage
         tell me to  set  crash_id to  do  shell script  "echo "  & quoted form of msgContent &  " | sed -E -n 's_.* crash_id:(.+)}_\\1_1p'"
         if  crash_id  is  not  in  crash_id_set and the length of crash_id >  0  then
             set  crash_id_set to crash_id_set & crash_id
         end  if
     end repeat
     
     repeat  with  crash_id  in  crash_id_set
         set  param to param &  "%22"  & crash_id
     end repeat
     
     tell me to  do  shell script  "cat ~/Documents/AppleScripts/ios_crash_url | sed -n -E s_crash_ids_"  & quoted form of param &  "_p | xargs open " end tell

url 原始信息保存在文件 ios_crash_url 中,使用 sed 作简单替换以后,将 url 传递个 open 命令便可。

最后添加个命令 alias,就能够作到一键完成了。

1
alias ioscrash= 'osascript /Users/fenggao/Documents/AppleScripts/outlook_ios_crash.scpt'

代码重构

我还使用过 AppleScript 来重构 Objective C 代码,原理很简单,将 Xcode 中选中的代码以 text 的形式传递给 AppleScript,再经过 AppleScript 传递给命令行来操做。或者将 Xcode 当前打开的类文件 path 经过 AppleScript 传递给命令行工具,接下来就是基础的文件操做了,各种工具任由你选,好比咱们可使用本地编译好的 clang 来分析类文件,来进行针对 Objective C 语法特征的文本修改。当咱们有大量的代码文件须要修改,并且修改的规则遵循某个相同的 pattern 时,使用脚本能起到事半功倍的效果。

经过 osascript 命令执行 AppleScript 是方式之一,另外一种方式是经过 Service。每一个 App 在菜单里都有 Services 一项。咱们能够经过 Automator 来添加每一个 App 都能使用的 Service。

咱们能够把一个 Service 想象成一个 workflow,而一个 workflow 能够包含若干个 action,执行 AppleScript 就能够是其中的一个 action。

首先经过 Spotlight Search 启动 Automator,启动以后选择建立 Service。以后能够看到因此支持的 action,选择 Run AppleScript 并拖动到右侧的 workflow 区域,便可执行某个 AppleScript 了。固然也能够拖动 Run Shell Script 到 workflow 区域,各个 action 之间能够经过 stdin 传递数据。以下图所示:

 

applescript01.png

全部建立保存以后的 service 都会自动保存到 ~/Library/Services/ 目录下,一旦保存咱们就能够在应用的 services 目录下看到咱们的目标,好比我保存 xcode-text.workflow 以后。我在 Xcode 中选择某些代码,右键就能够看到我所建立的 service 了,如图:

 

applescript02.png

关键字:automator->service->action->applescript

总结

AppleScript 的应用场景很普遍,且很容易上手。一些 Mac App 的核心功能甚至都是利用 AppleScript 来编写的。好比 Mac 上的剪贴板工具,就是经过 AppleScript 来操做其余应用的当前编辑文本,来实现历史查找和插入功能。工具的强大与否在于使用之人如何用之,工具都是越用越称手。