那么让我们重新审视AppleScript的错误wrote about two weeks ago, where System Events returns the wrong folder in response to a
set p1 to path to application support folder from user domain -- alias "Tycho HD:Users:gruber:Library:Application Support:" tell application "Finder" set p2 to path to application support folder from user domain -- alias "Tycho HD:Users:gruber:Library:Application Support:" end tell tell application "System Events" set p3 to path to application support folder from user domain -- alias "Tycho HD:Library:Application Support:" end tell
path to <some magic folder name> from user domain命令将从中返回文件夹local domain（根级库文件夹）而不是。
Thanks to dozens of helpful emails from various readers (and I thank each of you), it’s clear why this is happening: it’s a good old-fashioned scripting dictionary terminology conflict.
路径” command, which takes an optional “
用户域” as a constant, with the four-character Apple Event code ‘fldu’.
用户域”, not as a constant, but rather as a property of the System Events application itselfIt uses the same four-character Apple Event code, ‘fldu’.
Bear with me here, because we need a little background on how AppleScript works to truly fathom just how pernicious this particular bug is.
Compiled AppleScripts are not stored as AppleScript source code; instead, as the name of the format implies, they are stored in a compiled format, which format consists of Apple Event codesScripting dictionaries are the go-between; they map the English-like syntax of AppleScript to the underlying Apple events:
AppleScript源代码⇄ scripting dictionaries ⇄ Apple events
翻译有两种方式You type AppleScript syntax, then when you compile the script, it gets translated to Apple eventsWhen you open a saved script, AppleScript uses the dictionaries to translate the compiled Apple events back into English-like AppleScript source code.
用户域列举However, when we put this statement in a System Events tell block, System Events’s dictionary gets the first crack at the terms, and because it has its own definition of
用户域, that’s the one AppleScript uses因为它使用相同的AppleScript语法和the same underlying Apple Event code, there is no indication to you, the programmer, that AppleScript has resolved
用户域to something other than StandardAdditions’
So it compiles successfully, and when it decompiles back into AppleScript source code, the syntax looks correctBut when it executes, it returns the wrong result.
丹尼尔Jalkutwas the first of several readers to suggest the following workaround:
A stupid, but functional workaround would be to define your own “user domain” key outside the scope of the System Events tell. For instance, if you were going to be doing a bunch of this stuff in a script, you could do something like this:
set myUserDomain to user domain tell application "System Events" path to application support from myUserDomain end tell
myUserDomaingives you a reference to StandardAdditions’
用户域enumeration from within the context of a System Events tell block.
Another workaround suggested by several readers is to use System Events’s own means of getting references to special folders, rather than StandardAdditions’
路径命令For example, to get a reference to the Fonts folder in the user domain:
tell application "System Events" set ff to fonts folder of user domain end tell
But that doesn’t return a path or an alias; instead it returns a System Events
夹class contains properties for the path (HFS-style) and POSIX path, so if what you want is the path (rather than a folder object), you can say something like this:
tell application "System Events" set ff to fonts folder of user domain set posix_path to POSIX path of ff set hfs_path to path of ff end tell
posix_pathwill be something like “/Users/gruber/Library/Fonts”, and hfs_path will be something like “Tycho HD:Users:gruber:Library:Fonts:”.
tell application "System Events" set ff1 to path of fonts folder of user domain end tell
set ff2 to path to fonts folder from user domain
of user domain” versus “
这是最糟糕的AppleScriptIt was a grand and noble idea to create an English-like programming language, one that would seem approachable and unintimidating to the common userBut in this regard, AppleScript has proven to be a miserable and utter failure.
path of fonts folder of user domain path to fonts folder from user domain
But in AppleScript, they are not, and rather are brittlely dependent on the current contextIn the global scope, the StandardAdditions OSAX wants “path至“和”从user domain”; in a System Events tell block, System Events wants “path的“和”的用户域“。
The idea was, and I suppose still is, that AppleScript’s English-like facade frees you from worrying about computer-science-y jargon like classes and objects and properties and commands, and allows you to just say what you mean and have it just work.
But saying what you mean, in English, almost never “just works” and compiles successfully as AppleScript, and so to be productive you still have to understand all of the ways that AppleScript actually worksBut this is difficult, because the language syntax is optimized for English-likeness, rather than being optimized for making it clear just what the fuck is actually going on.
In this regard, AppleScript syntax styling in your chosen script editor can provide essential cluesHere’s what the above examples look like on my machine in脚本调试器：
The gray words are language keywords, meaning they are part of the AppleScript programming language; the blue words are application keywords, meaning they are defined by a scripting dictionary.1
Note that in the first statement, inside the System Events tell block, the “
path of“是一种语言关键字But in the second statement, the “
路径“是一个应用关键字Even more confusing is that “
至“， 哪一个 ”
How is this possible? Because the second “
至” is not a standalone keyword; it’s part of StandardAdditions’ “
路径” command, which is a single token that consists of multiple space-separated wordsIn most languages, this command would have been called something like “
pathTo“ 要么 ”
path_to”; but in AppleScript, intra-token spaces are considered a good thing, on the grounds that they greatly increase the resemblence to EnglishIn practice, however, I believe intra-token spaces are one of the most common underlying causes of AppleScript confusion.
路径syntax, the “
来自用户域” is an application keyword; it’s the name of a parameter defined by the
路径命令Whereas in the System Events syntax, it’s just another chained “
的” to access a property of an object.
These prepositional differences are even more exasperating when you consider that “
在“在AppleScript中可以互换If you can say either of these to mean the same thing within a System Events tell block:
path of fonts folder of user domain path in fonts folder in user domain
从” might be interchangeable with other prepositions as wellBut you can’t, and if you’re not aware that StandardAdditions’s “
路径” is a single token of two words, it seems rather arbitrary, if not downright random, which prepositions are allowed where.
一个’s — “
get path of fonts folder“，实际上意味着同样的事情”
get the the the path of the the the fonts folder” — makes it seems as though AppleScript just doesn’t care about “little words”, which is true in a handful of cases, but completely untrue in others.)
path to fonts folder from user domain“可能是这样的：
path_to（“fonts folder”，“user domain”）
The point being that in most languages, these two calls don’t look at all similar这是件好事，因为他们不at all similar: one is a global command taking two parameters, the other is a property of a property of an objectAppleScript’s slavish devotion to English-likeness, on the other hand, gives us two very different syntax constructs that read, to humans, as though they’re semantically similar.
One way to disambiguate the two syntaxes in these examples would be to use AppleScript’s
的(apostrophe-s) “possessive” operator instead of the “
的“关键字The two statements in the following example are more or less equivalent:
tell application "System Events" set ff1 to path of fonts folder of user domain set ff2 to user domain's fonts folder's path end tell
马特·纽堡，他的精彩AppleScript: The Definitive Guide, devotes an entire section to what he calls “The ‘English-likeness’ Monster” (from which section I’ve taken the title of this essay)He establishes numerous problems caused by AppleScript’s attempts to resemble English, and concludes by pointing out that even simple variable assignment in AppleScript suffers:
然后有一个事实是英语很冗长In most computer languages, you would make a variable
Xtake on the value 4 by saying something like this:
x = 4
copy 4 to x set x to 4
Doubtless not everyone would agree, but I find such expressions tedious to write and hard to readIn my experience, the human mind and eye are very good at parsing simple symbol-based equations and quasi-mathematical expressions, and I can’t help feeling that AppleScript would be much faster to write and easier to read at a glance if it expressed itself in even a slightly more abstract notational style.
tell application "System Events" set ff1 to path of fonts folder of user domain end tell
You might be tempted to say, “Well, there you go — when you’re inside a System Events tell block, don’t use the StandardAdditions
路径command, use System Events’ own means of accessing special folders instead.”
The problem here is that System Events doesn’t know about as many special folders as does StandardAdditionsOr, more specifically, the System Events dictionary doesn’t define names for as many special folders as does the StandardAdditions dictionary.
And, unfortunately, one of the folders System Events doesn’t know about is the one we’re interested in, the Application Support folder. Changing the above reference to the Fonts folder to:
tell application "System Events" set appsup to path of application support folder of user domain end tell
甚至不会编译As of Mac OS X 10.4.2, here is the full list of special folder properties known to System Events
StandardAdditions'字典定义了几十个，3but even it doesn’t include every special Mac OS folder.
完整列表，以四字符代码的形式，is available in Apple’s Carbon developer documentationThe folder names defined in System Events’ scripting dictionary are just wrappers around these four-character codes, so, to address one of the folders that the dictionary doesn’t define, you can simply use the raw code:
tell application "System Events" set appsup to path of folder id "asup" of user domain end tell
tell application "System Events" set appsup to user domain's folder id "asup"'s path end tell
So, at last, we’ve arrived at a complete workaround, but it requires (a) foreknowledge of the underlying
用户域terminology conflict; and (b) looking up the Application Support folder’s four-character code in the Carbon developer documention.
My advice is not to use scripting addition commands from within application tell blocks if you can avoid itUse tell blocks only to group statements directly related to the app that is the target of the tell blockYou’re better off with multiple tell blocks for the same app interspersed with calls to scripting addition commands than a single tell block that contains calls to scripting additions.
The blame for my complaint here probably lies mostly with System Events, because its dictionary should not define a
用户域enumeration in such a way that it doesn’t produce a compile- or run-time errorOr, perhaps the blame lies mostly with the AppleScript compiler for allowing this terminology conflict to procede without error.
But I’ll also point an accusatory finger in the direction of scripting additions in generalThe problem with scripting additions is that they pollute the global namespace with their dictionary syntaxAn application can define whatever crazy terms it wants and it won’t adversely affect the rest of your script, because an app’s terms are only available within tell blocks targeting that app（或者在...内
AppleScript is actually a tiny language, with extraordinarily few keywords, but the standard scripting additions turn it into a bigger language, ripe for terminology conflicts.
临时物品文件夹” from the user domain using either StandardAdditions or System Events, and you’ll get the path to “~/Library/Caches/TemporaryItems” instead of a sub-folder within “/private/tmp” or “private/var/tmp” (which is where