AppleScript Tips for Shell Scripting

OS X is surprisingly scriptable, including OS X applications. (Especially Apple’s applications). This is the good news. The bad news is that said scripts are difficult to write and debug, and they don’t play very well with Unix-style shell scripts. (Manipulating Unix-style filenames is especially painful.)

Here’s an example of what can be done: select works like open except that it opens a Finder window with the arguments selected:

$ select *.gif

The AppleScript code is complicated and involves far more workarounds than it really should but, hey, it does work.

Tips

Some tips and tricks in no particular order.

Basics
  • Use & for string concatenation: return "Hello, " & name
  • Use as [type] to coerce to a string (you’ll need this for sane debugging): return foo as string would be written in C-like languages as return (string) foo
  • Built-in properties can contain spaces: track number of current track is equivalent to something like currentTrack['trackNumber'] in JavaScript
  • AppleScript tries to be English-like (never a good idea): assignment is via set foo to bar (not set foo = bar) and you see things like count of every media item of container src
Debugging

log to dump output for debugging, though note that some types are coerced into strings for output–compare the output of log obj and log class of obj if not sure.

Script Editor

osascript’s error messages are pretty awful; for a slightly (slightly!) better development experience, use the Script Editor application. This gets you syntax highlighting, and slightly better log messages.

For best results click on the “page” icon in the bottom of the window to reveal the “messages” tab:

(Unfortunately Script Editor can’t open files that start with a shebang (see below)–you’ll need to copy and paste AppleScript to and from a text editor into Script Editor.)

Shell scripting

There’s a few different ways you can run AppleScript from the command line. First of all, you can use the standard #! shebang with osascript as the interpreter:

$ cat hello.sh
#!/usr/bin/osascript

return "Hello, World"
$ chmod +x hello.sh
$ ./hello.sh
Hello, World

To read arguments, use the run method:

$ cat hello.sh
#!/usr/bin/osascript

on run argv
  return "Hello, " & item 1 of argv
end run
$ ./hello.sh Clem
Hello, Clem

You might often find that you often want to do some pre-processing via bash, especially for anything that involves filenames. This can be achieved (as in the select example) via a bash “heredoc”:

#!/bin/bash

# bash code
if [ $# == 0 ]; then
    echo "usage: $(basename $0) args"
    exit
fi

# AppleScript code
/usr/bin/osascript - "$@" << END

on run argv
  # ...
end run

END
Applications API

Use Script Editor’s “File | Open Dictionary…” to figure out what different applications let you do via AppleScript. Apple applications often expose a reasonably large API; for others you might get something minimal, or even nothing at all.

Spotify, for example, only lets you play/pause/next/prev. You can also get some information about the currently-playing track. One the other hand Apple Photos has a fairly rich API. (Example script.)

Working with filenames

Need the current working directory?

set pwd to do shell script "pwd"

Create file object from Unix-style path (with “/”):

(POSIX file unixpath)

Get Unix-style path from a file object:

(POSIX path file)

For more information on handling filenames, see: