By John Gruber
Little Streaks: The to-do list that helps your kids form good routines and habits.
The Standard Additions scripting addition defines the path to
command; you tell it which folder you want, it returns an alias
pointing to that folder.
So, for example, you can say:
set p1 to path to application support
And it will return an alias to the “Application Support” folder in
your top-level Library folder. Aliases use HFS-style paths, so the
result (p1
in this case) will look something like this:
Tycho HD:Library:Application Support:
There are a couple of dozen special folder names you can pass to path
to
, including documents folder
, favorites folder
, desktop
, and
so forth. Consult the Standard Additions scripting dictionary for the
full list.
Because of the layered system folder layout on Mac OS X, there are more than one instance of some of these folders. For example, with the “Application Support” folder, there’s one in the top-level “Library” folder, and there’s another one inside the “Library” folder in each user’s home folder.
These different layers are called file-system domains in Mac OS X’s
parlance.1 You can pass the path
to
command a from
parameter, which allows you to specify which
domain you want. As evidenced above, if you omit the from
parameter,
it defaults to the Local domain (i.e. the top-level “Library” folder
shared by all users).
To get the current user’s “Application Support” folder, ask for the User domain:
set p1 to path to application support from user domain
This returns something like:
Tycho HD:Users:gruber:Library:Application Support:
So, given all that, take a guess what this returns:
tell application "System Events"
set p2 to path to application support from user domain
end tell
The reasonable guess, of course, is that it would return the same
thing. Alas, no. Instead, in the above snippet, p2
is set to:
Tycho HD:Library:Application Support:
I.e. by placing the path to
command within a tell application
"System Events"
block, it no longer honors the from user domain
parameter, and instead always returns the folder from the Local
domain.
This is particularly insidious because inside a tell application
"System Events"
block is exactly where you’re likely to want to get
the path to a folder, because you can’t do much with an alias to a
folder except within such a block. AppleScript, by itself, doesn’t let
you do anything with a folder.
For example, let’s say you want to get a list of every item within the user’s “Application Support” folder. You can’t just say this:
set p to path to application support from user domain
set my_list to every item of p
because you’ll get an error on the every item of
part. You need to
ask an application that knows how to do something with a folder. The
Finder can do this, but the recommended way to script this is to use
System Events instead. But you can’t just say this:
tell application "System Events"
set p to path to application support from user domain
set my_list to every item of p
end tell
because once you move the path to
command into the System Events
tell block, you get the wrong answer. Instead, you have to remember
this, and write it like this, with the path to
statement outside the
tell block:
set p to path to application support from user domain
tell application "System Events"
set my_list to every item of p
end tell
The Finder, however, does not suffer from the same bug as System Events.2 This works as expected:
tell application "Finder"
set p to path to application support from user domain
set my_list to every item of p
end tell
The reason to prefer System Events over Finder for this sort of thing is that, ostensibly, Finder is technically “optional” — users of third-party file managers like Path Finder might not be using the Finder. System Events, however, is always available.
This sort of bug is precisely why so many people despise AppleScript.
Not only does it make no sense, but something like this can be
maddeningly difficult to track down. Imagine if you start with the
path to
statement outside the System Events tell block, and
everything is working as you expect. Then, while cleaning up the code,
you move the path to
statement into the tell block, to keep it next
to the other lines of code that pertain to the folder you’re getting
the path to.
Now your script is broken — but you may not notice immediately,
because it doesn’t break with a compilation or runtime error. Instead,
just by moving the path to
statement inside the System Events tell
block, it silently starts returning a different (and wrong)
“Application Support” folder.
For those of you keeping score at home: Radar 4255244.
Cf. “The One and Only Mac OS X Extensions Folder” for more details about Mac OS X’s file-system domains. ↩
I have to assume this is a bug in System Events. If this isn’t a bug, but instead expected behavior, I’d love the explanation. Also note that this behavior is the same on 10.3.9 and 10.4.2. ↩