在Yosemite上使用JavaScript for Automation列出文件夹中的所有文件

时间:2014-10-10 14:23:21

标签: javascript automation applescript osx-yosemite javascript-automation

我正在尝试将一些旧的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)
-- > []

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

3 个答案:

答案 0 :(得分:13)

就像之前的Leopard's 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而不是items,JXA似乎有效:

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

这表明JXA沉溺于同样的内部"聪明"导致SB打破这么多应用程序。 (请注意,我在早期的测试中发现了许多这样的设计缺陷,但是一旦明确了AS开发人员只关心强加他们自己的个人意识形态和对其他人的偏见,残缺的能力和破坏的兼容性被诅咒就放弃了。)

为了进行比较,这里是JavaScriptOSA (JOSA) prototype我为JXA开发人员快速组建的reference forms'几个月前参考(他们很快忽略了它,自然):

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对范围,过滤器,相对和插入{{3}}的支持;它特别糟糕。)

答案 1 :(得分:7)

"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)
    );
});

答案 2 :(得分:2)

我可以像这样得到它

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

- &GT; [“bin”,“lib”,“libexec”,“sbin”,“share”,“standalone”,“X11”]

即便如此:

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

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