Last week I was feeling tired of dealing with random AppleScript errors and bugs caused by my complete lack of understanding of the language. I ran across Apple’s AppleScript Language Guide (pdf), which gives a good overview of the language and explains why some things happen they way they do.
I am by no means an AppleScript expert, but here are a few useful things I learned from reading the guide. If you ever AppleScript, set aside an hour to read the guide.
There are three ways to specify a file in AppleScript
alias "Macintosh HD:Users:grigg:Desktop:notes.txt"
POSIX file "/Users/grigg/Desktop/notes.txt"
file "Macintosh HD:Users:grigg:Desktop:notes.txt"
An alias
can only refer to a file that already exists. Once an alias
is defined during the run of a script, it will refer to the same file even if it is moved or renamed.
Both POSIX file
and file
refer to filesystem locations instead of files. If you want to refer to a file which does not yet exist, you must use one of these. The only difference between the two is that POSIX file
requires paths in POSIX notation, and file
requires paths in classic Mac notation.
If you need an alias
but prefer to specify paths in POSIX form, you can use
POSIX file "/Users/grigg/Desktop" as alias
If you have an alias
or file
and want the POSIX name, use POSIX path of
the object.
Relative paths are not supported (except when run from a shell; see below) and tilde expansion is not supported.
If you want to run an AppleScript from the command line, you can save the AppleScript as plain text with the interpreter listed in the first line:
#! /usr/bin/osascript
Then make it executable using chmod +x
, and run it like you would any other shell script. Of course, your system will need to compile such scripts each time they are run, which in my quick experiment added only 10 to 30 milliseconds of overhead.
If you want to store your AppleScript as plain text but run a compiled version, you can use osacompile
. If script.applescript
is saved as plain text, then
osacompile -o script.scpt script.applescript
saves a compiled version as a binary file script.scpt
. To run the compiled version, you will need to run osascript script.scpt
.
AppleScripts run from the command line print their return value (or the result of the last expression, if there is no explicit return) to the output stream.
AppleScripts run from the command line can accept arguments (which are passed as a list to the run
handler) and can use relative paths. The following script prints the full Mac-style path to the file listed as first argument.
#! /usr/bin/osascript
on run(arguments)
set filename to POSIX file (first item of arguments) as alias
return filename as string
end run
AppleScript allows you to define variables using pipes as delimiters, for example |variable|
, |my variable|
, or |2^5|
. Naming a variable |2^5|
is probably not a good idea, but pipes can still be useful because of the way the AppleScript Editor treats them.
AppleScript reserves a lot of words for its own use. If you are sending commands to another application, this will also reserve a bunch of words. So if you need a variable name, there is a good chance you will accidentally use something you aren’t supposed to, which results in cryptic and annoying errors. Some people get around this by prefixing variables with my
or the
, as in theFile
or myInteger
. I have been known to use excessive underscores.
Another way around this issue is to use bars. The best thing is that AppleScript Editor removes them if they are not necessary. So you you write |variable|
and nobody else is claiming this word, the editor will remove the bars when you compile or run, giving you confirmation that you are free to use this word.
AppleScript deals with variables pretty much the same as Python. Lists and records (dictionaries) are mutable and passed by reference. Strings and numbers are immutable and essentially passed by value.
For example,
set a to {1,2}
set b to a
copy 3 to end of a
-- now a and b are both {1,2,3}
You can use copy a to b
to create a deep copy or set b to items of a
to create a shallow copy.
In AppleScript you can force pass by reference using the term a reference to
.
on change_to_5(b)
set contents of b to 5
end change_to_5
set a to 0
change_to_5(a reference to a)
-- Now a = 5
This can also be useful when dealing with long lists. According to the Language Guide, the most efficient way to append to a list is
copy 5 to end of (a reference to long_list)
I don’t understand why.
I don’t know if I would ever actually use this, but I thought it was interesting. If you write
set mixed_set to {1, 1.2, 3, "hello", 5}
integers of mixed_set
then AppleScript returns {1, 3, 5}
. You can also write integer 3 of mixed_set
to get 5
.