10

我正在尝试将一些旧的 Applescript 移植到新的 JavaScript 语法中。

有些事情似乎很简单,所以:

tell application "System Events" to keystroke "t" using command down

变成:

System = Application('System Events');
System.keystroke("t", {using: "command down"})

但是,我一生都无法弄清楚如何在特定位置列出文件。在 AppleScript 中,要返回目录中的文件列表/usr,您可以:

tell application "System Events" to set fileList to name of items in folder "/usr"
-- > {"bin", "include", "lib", "libexec", "local", "sbin", "share", "standalone", "X11"}

但是,我终其一生都无法弄清楚如何用 Javascript 来实现。

System = Application('System Events')
myPath = Path("/usr")

fileList = System.items(myPath) 
-- > message not understood

fileList = System.folder(myPath)
-- > message not understood

fileList = System.diskItems(myPath)
-- > []

fileList = System.diskItems({at:myPath)
-- > []

我也尝试了很多其他组合,但没有运气。有任何想法吗?

4

3 回答 3

13

就像之前的 Leopard 的 Scripting Bridge一样,JXA 有意破坏各种在 AppleScript 中完美运行的东西。以下是将原始 AppleScript 命令翻译成 JXA 语法:

//tell application "System Events" to name of items in folder "/usr"
Application('System Events').folders.byName('/usr').items.name()

AS 版本完美运行,但 JXA 等价物只是抛出一个完全没有意义的Error -1700: Can't convert types.

diskItems如果您编写而不是,JXA 似乎确实有效items

Application('System Events').folders.byName('/usr').diskItems.name()
// --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]

这表明 JXA 沉迷于导致 SB 在这么多应用程序上中断的相同内部“聪明”。(请注意,我在早期的测试中发现了许多这样的设计缺陷,但一旦明确 AS 开发人员只关心将自己的个人意识形态和偏见强加于其他人,我就放弃了报告它们,该死的能力和兼容性受损。)

为了比较,这是几个月前我快速整理的JavaScriptOSA (JOSA) 原型,供 JXA 开发人员参考(他们很快就忽略了它,natch):

app('System Events').folders.named('/usr').items.name()
// -> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]

(虽然没有完全完成或测试,但 JOSA 仍然比 JXA 工作得更好,有更好的文档记录,甚至包括一个用于将 AS 命令转换为 JS 语法的自动翻译工具。不幸的是,因为 Apple 已经遗留或弃用了 AEM,CM 、PM 和 OSA Carbon API,我不推荐将其用于生产用途;它纯粹是为了比较目的。)

相似地:

set myPath to POSIX file "/usr"
tell application "System Events" to name of every disk item of folder named myPath
--> {"bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"}

myPath = Path('/usr')
Application('System Events').folders.byName(myPath).diskItems.name()
// Error -1728: Can't get object.

var myPath = Path('/usr')
app('System Events').folders.named(myPath).diskItems.name()
// --> ["bin", "lib", "libexec", "local", "sbin", "share", "standalone", "X11", "X11R6"]

您可以通过将 Path 对象转换为字符串并使用它来解决该特定情况:

myPath = Path('/usr')
Application('System Events').folders.byName(myPath.toString()).diskItems.name()

尽管这种解决方法在其他情况下不一定有帮助;例如,它在 Finder 中失败,因为 Finder 不理解 POSIX 样式的路径字符串,并且无法从 JXA Path 对象中获取 HFS 样式的路径字符串(Finder 可以理解):

set myPath to POSIX file "/usr"
tell application "Finder" to name of every item of item myPath
--> {"X11", "X11R6", "bin", "lib", "libexec", "local", "sbin", "share", "standalone"}

myPath = Path('/usr')
Application('Finder').folders.byName(myPath.toString()).items.name()
// Error -1728: Can't get object.

就这样。(例如,尝试测试 JXA 对范围、过滤器、相对和插入引用形式的支持;它特别烂。)

于 2014-10-11T17:10:40.660 回答
8

"System Events"方法确实具有简单的优点,但事实证明,使用$.NSFileManager(现在直接可用于脚本)可以显着提高性能。

在我的系统上,开始比较

var strPath = '/usr';

var appSys = Application('System Events'),
lstHarvest = appSys.folders.byName(strPath).diskItems.name();

几千次迭代的快速测试表明,我们可以通过这种略带巴洛克风格的方法将其持续加速 40%:

var strPath = '/usr';
var fm = $.NSFileManager.defaultManager,
    oURL = $.NSURL.fileURLWithPathIsDirectory(strPath, true),
    lstFiles = ObjC.unwrap(
        fm.contentsOfDirectoryAtURLIncludingPropertiesForKeysOptionsError(
            oURL, [], 1 << 2, null
        )
    ),
    lstHarvest = [];

lstFiles.forEach(function (oItem) {
    lstHarvest.push(
        ObjC.unwrap(oItem.path)
    );
});

并且使用更简单的方法超过 300%:

var strPath = '/usr';
var fm = $.NSFileManager.defaultManager,
    lstFiles = ObjC.unwrap(
        fm.contentsOfDirectoryAtPathError(strPath, null)
    ),
    lstHarvest = [];

lstFiles.forEach(function (oItem) {
    lstHarvest.push(
        ObjC.unwrap(oItem)
    );
});
于 2015-02-05T21:00:39.450 回答
2

我可以这样得到

 foldersList =  foldersList =  System.folders.byName("usr").folders.name()

-> [“bin”、“lib”、“libexec”、“sbin”、“share”、“standalone”、“X11”]

即使这样也有效:

   foldersList =  System.folders.byName("/Users/USERName/Documents/").folders.name()

但到目前为止,除了“打开”之外,我无法让 Path 命令处理任何事情

于 2014-10-11T08:24:38.470 回答