路径问题 - POSIX HFS 无法获取文件夹

Path Issues - POSIX HFS Cannot get folder

我正在尝试让这个简短的脚本发挥作用。它应该做的就是将本地用户的应用程序 Support/App 中的文件夹内容移动到 USB。

set localLocation to POSIX path of (path to library folder from user domain) & "Application\ Support/myApp" as text
set usbLocation to "/Volumes/myUsb/myApp"                                   
tell application "Finder" to move entire contents of folder localLocation to folder usbLocation

两个目录(USB 和计算机)中都有一个文件夹可用,它与此处描述的自定义路径描述相匹配 "myApp"。该代码在 tell 的第一部分有一个错误,它无法在 Application Support 中找到该文件夹​​。我不确定为什么会这样,而且我也在努力理解 HFS 和 POSIX 之间的区别,应该使用哪个?我有一种感觉,类型可能存在连接错误。我是初学者,请帮忙

谢谢!

了解 AppleScript 如何处理文件和文件夹引用是一件令人头疼的事情,而且众所周知,它对文件说明符和路径字符串的处理令人费解和挑剔。

简单定义:

Posix path: A path made up of forward slashes that separate folders in a directory tree, e.g. /Users/CK/Downloads/Some_File.txt. The root (top-level) directory is represented by a single forward slash, /. Every posix path is descended from this root directory, so, generally speaking, posix paths must start with a forward slash. Folder paths ideally end with a terminating forward slash; file paths do not; but this is not strict.

HFS path: A path made up of colons that separate folders in a directory tree, e.g. Macintosh HD:Users:CK:Downloads:Some_File.txt. The root directory is represented by Macintosh HD:, which always begins an HFS path (unless your system hard drive is called something else). Folder paths ideally end with a terminating colon; file paths do not; this is semi-strict.

这就是您执行一些 AppleScripting 所需了解的有关 posix 路径和 HFS 路径的全部信息。困难的部分是掌握 AppleScript 的文件 class 类型。一共有三个:

alias: These are your friends, and are the most versatile when used with either Finder or System Events, and when referring to either files or folders. They are an AppleScript object that contain a file reference that points to an existing file. Trying to assign an alias class type to a file reference of a file that does not exist will throw an error.

file: These are a file reference object that may point to a file that doesn't exist (yet). It qualifies an HFS path string, identifying it as not just a piece of text, but a path to a file. The key difference between file and alias is that file is a static reference, meaning that if it points to a file with a given name, and that file's name changes, the file object will now reference a file that does not exist. An alias, on the other hand, dynamically shifts its reference even after a file is renamed or moved.

POSIX file: If you like using posix paths (and you should), the POSIX file object is your best friend. It takes a posix path string and qualifies it as a path to a file in much the same way file does for HFS path strings. Likewise, it is a static reference and can point to files or folders that don't exist.

我的推荐

我的感觉是,HFS 路径对于命令行用户和 AppleScripting 之间本来可以轻松交互的公式来说是一种不必要的复杂化。它们确实会让人们感到困惑,并且由于通过 AppleScript 返回的结果广泛观察到这种表示法,因此它们在使用中似乎是强制性的。

他们不是。就我个人而言,从不 使用 HFS 路径。 (几乎从不)。

一个本质上并不比另一个好,这实际上只是个人喜好。所以我的建议是选择一种您最喜欢的样式,并学习如何在 AppleScript 设置中操作该类型的路径。

当我使用 posix 路径时,我关心 POSIX file 个对象和 alias 个对象。这就是我现在将重点关注此答案的其余部分。

你的脚本

您的脚本抛出了第一个错误,因为您试图转义文件路径字符串中的空格,这可能是在终端中键入的习惯。你不需要转义文件字符串中的任何字符,除了反斜杠\,因为文件路径字符串总是用双引号括起来。

仍在处理脚本的第一行,您已经非常正确地检索了 path tolibrary folder(其中 returns 和 alias);把它变成 posix 路径字符串;然后附加 "Application Support/myApp" 路径文本。但是,了解您实际上可以获得 path toapplication support 文件夹可能会有所帮助,因此您的第一行可以变为:

set localLocation to POSIX path of (path to application support from user domain) & "myApp"

结果是 posix 路径 字符串 ,但不是文件对象(但目前没问题)。

然后你的下一行显式声明一个 posix 路径字符串:

set usbLocation to "/Volumes/myUsb/myApp"

绝对没问题。

接下来是棘手的事情:使用 Finder:

tell application "Finder" to move entire contents of ¬
    folder localLocation to folder usbLocation

就是说,您 几乎 完美。因为您正在使用 posix 路径,所以您需要将它们变成 alias 对象,或者向 finder 解释它正在处理 posix 路径,这就是 POSIX file 对象确实如此。

要创建一个 POSIX file 对象,您可以在 posix 路径字符串前添加 POSIX file 说明符,如下所示:

set usbLocation to POSIX file "/Volumes/myUsb/myApp"

或者像这样对 class 类型进行更传统的强制转换:

set usbLocation to "/Volumes/myUsb/myApp" as POSIX file

无论哪种情况,AppleScript 都会将其转换为 file 对象并将其转换为 HFS 路径。如果你 运行 上面那一行本身,AppleScript returns this:

file "Macintosh HD:Volumes:myUsb:myApp"

因此,我们已经可以看到 file 对象和 HFS 路径与 POSIX file 对象和 posix 路径之间存在等效性。

您可以选择编辑脚本的第 1 行和第 2 行以立即构建这些 POSIX file 对象;或者您可以在与 Finder:

交互时执行此操作
tell application "Finder" to move entire contents of ¬
    folder (localLocation as POSIX file) to folder (usbLocation as POSIX file)

如果在这里这样做,你必须强制使用 as,可能是因为将它作为对象说明符放在前面会干扰 folder 的作用对象说明符。

这应该会成功地将所有文件移动到新位置。另一种方法是移动文件夹而不是其内容,如果有很多文件和子目录,这可能会更快。只需相应地更改目标路径:

set localLocation to POSIX path of (path to application support folder from user domain) & "myApp" as POSIX file
set usbLocation to POSIX file "/Volumes/myUsb/"

tell application "Finder" to move folder localLocation to folder usbLocation with replacing

with replacing 是因为目的地中的文件夹 myApp 将被来自您硬盘驱动器的文件夹 myApp 替换。)

最后,为了完整起见,我将简要谈谈 alias 个对象:

别名对象

从 posix 路径构建 alias 对象相当简单,需要两个步骤。首先,如上所示构造 POSIX file 对象。然后,您将此对象强制转换为 alias。一行即可完成:

set usbLocation to POSIX file "/Volumes/myUsb/myApp" as alias

set usbLocation to "/Volumes/myUsb/myApp" as POSIX file as alias

但是请记住,alias 对象指向已经存在的文件和文件夹。因此,在某些情况下,您可以立即从指向一个不存在的文件的 posix 路径字符串中声明您的 POSIX file 对象,例如,您将要创建的文件。但是您只能在创建文件后将其强制转换为 alias

您可能想要使用 alias 对象的一个​​原因是因为它们是动态的,正如我之前提到的(或者,它们 应该 是)。因此,如果您在开始时将 localLocation 设置为 alias 对象,然后将文件夹移动到其目标位置,就像在我最后一个 Finder 示例中一样,alias object 现在应该自动指向 /Volumes/myUsb/myApp/(尽管它并不总是成功,因为 AppleScript 有许多错误之一)。

使用 alias 对象的另一个更重要的原因是它们直接在与 AppleScript 交互的不同应用程序之间转换:并非所有应用程序都使用 POSIX file 对象,有些可能不使用 HFS 路径;但他们几乎都知道 alias 对象是什么。

这是在 FinderSystem Events 之间切换文件处理的关键。一般来说,文件和文件夹处理最好使用 System Events 而不是 Finder。但是,有几件事只能在 Finder 中执行:设置文件标签 (label index);获取选定的文件 (selection);并知道当前哪个目标文件夹具有焦点 (insertion location)。

Finder returns Finder-specific classes 中检索 selection,即document files。不能通过 System Events 使用这些对象。但是,selection as alias list 可以通过 System Events:

进行操作
tell application "Finder" to set S to selection as alias list

tell application "System Events" to get properties of item 1 of S

最后,使用 alias 对象的第三个原因是,出于某种原因,将文件作为 alias 对象检索比作为任何其他 class 对象检索文件要快得多。对我的下载文件夹的内容进行测试(它足够小,不会让我等待,但足够大,可以让 Finder 工作),结果是:

tell application "Finder" to get entire contents of ¬
    (path to downloads folder) as alias list
-- 1.45s

tell application "Finder" to get entire contents of ¬
    (path to downloads folder)
-- 2.29s

它们是相同的语句,除了第一个中对 alias listalias 文件对象的列表)的强制转换。速度优势在较大的文件夹上会更加明显。

通过 Finder 使用 alias 对象比使用 filePOSIX file 对象稍微 easier/simpler,因为 alias 对象不会像其他两个那样区分文件和文件夹。在您的脚本中,Finder 必须将 folder 说明符与 POSIX file 对象一起使用;使用 alias 对象,您不需要:

set localLocation to POSIX path of (path to application support folder from user domain) & "myApp" as POSIX file as alias
set usbLocation to POSIX file "/Volumes/myUsb/" as alias

tell application "Finder" to move localLocation to usbLocation with replacing

我不同意被劝阻不要使用 HFS 路径。

如果您必须使用 Finder,这是最方便的方法,因为 Finder 不接受 POSIX 路径。

要在外部卷的顶层寻址文件夹,在 Finder 术语中还有另一种简短方法:folder "foo" of disk "bar"

set localLocation to (path to application support folder from user domain as text) & "myApp"                                  
tell application "Finder" to move entire contents of folder localLocation to folder "myApp" of disk "myUsb"

但是 entire contents 在 Finder 中可能会非常慢。 shell 快得多。

set localLocation to POSIX path of (path to application support folder from user domain) & "myApp/" 
set usbLocation to "/Volumes/myUsb/myApp"                                    
do shell script "/bin/cp " & quoted form of localLocation & "*" & space & quoted form of usbLocation