【问题标题】:How to write to standard data out using JavaScript or AppleScript multiple times?如何使用 JavaScript 或 AppleScript 多次写入标准数据?
【发布时间】:2018-01-11 04:21:13
【问题描述】:

如果我创建一个名为 myscript.js 的 AppleScript 脚本并将其传递给 oascript,它将执行一次 run 函数并将“hello world”写入标准数据输出:

function run(args) {

  for (var i=0;i<10;i++) {
     // out("number " + i); // execution error: Error on line 18: ReferenceError: Can't find variable: out (-2700)
  }

  return "hello world"; // written to standard data out
}

但如果我想多次写入标准数据输出,例如在 for 循环中,我该怎么做?

如果我执行以下操作,它会多次写入标准错误并在外部应用程序中调度多个事件:

  for (var i=0;i<10;i++) {
     console.log("number " + i);
  }

唯一的问题是它创建了错误事件而不是标准数据事件。

在脚本编辑器中,标准数据输出被发送到结果窗口。我想多次打印到结果窗口。

更新:
看起来这可能是不可能的。我找到了这句话here

问:我的脚本会在很长一段时间内产生输出。我如何阅读 他们进来的结果?

A:同样,简短的回答是你不会——shell 脚本不会 返回,直到命令完成。在 Unix 术语中,它不能用于 创建一个管道。但是,您可以做的是将命令放入 背景(参见下一个问题),将其输出发送到文件,然后 然后在文件填满时读取文件。

另外,请注意,如果我想使用 JavaScript 代替 AppleScript,我应该使用 cocoascript 代替 osascript 吗?

【问题讨论】:

  • 我认为您在 Unix-to-OSA (osascript) 和 OSA-to-Unix (do shell script) 通信之间感到困惑。您最初的问题询问如何实现前者 - 即如何使 AS/JS shell 进程将数据写入标准输出——而您新添加的脚注仅与后者相关。例如在 Node 中,您通常调用 console.log(…) 将消息打印到 stdout,调用 console.error(…) 打印到 stderr,或者如果您需要更大的控制权,请使用 process
  • 脚注说我无法将数据发送到standard data out,直到命令完成并通过return。我不知道这是否正确,因为如果我在脚本编辑器中并且我使用 console.log() 并将其附加到 Safari,它会将输出发送到 Safari 控制台。但如果我在我的 Adob​​e AIR 中运行它,console.log 会将数据发送到standard error out。如果我 return 脚本中的一个值,该值将发送到 standard data out
  • 忘记脚本编辑器。这是一个 OSA 环境,而不是 Unix 环境,因此不了解或支持 stdout/stderr/etc。给自己找一个像样的纯文本代码编辑器(例如我使用 BBEdit),将 #!/usr/bin/osascript -l JavaScript 放在脚本的顶部,然后将其作为 Unix shell 脚本运行。然后,您可以使用NSFileHandle.fileHandleWithStandardOutput().writeData(…) 直接写入标准输出,绕过对 OSA 施加的限制。但是,当最佳答案是完全避免 OSA 并首先使用正确的工具来完成工作(Python/Ruby/Node/等)时,这会很麻烦。
  • 谢谢。您提到了 JavaScript,但随后又提到了 NS 之类的东西。我猜目标C。我将不得不研究你所说的。现在我的 osascript 在 3 天后工作。我现在会在没有标准数据的情况下生活,或者使用其中一种技巧。
  • NS 是 Cocoa 类名的传统前缀,因为它们出现在 ObjC 和大多数 ObjC 桥接语言中(Swift 是一个明显的例外)。如果您打算使用 Cocoa API,那么您真的需要先熟悉 ObjC 语法,然后才能找到适合自己的方法。如果您不需要使用 Cocoa 或 Apple 事件,那么 JXA 除了making your life difficult 之外没有真正的价值;无论哪种方式,都有更好的选择:用于 Cocoa 开发的 Swift、用于桌面自动化的 AppleScript、用于所有 JavaScript 的 Node。

标签: javascript applescript osascript cocoascript


【解决方案1】:

“另外,我应该使用 cocoascript 代替 osascript 吗?”

TL;DR:如果你喜欢 JavaScript,也不Go Node!


长版:

JXA(用于自动化的 JavaScript)存在缺陷且不成熟,几乎没有用户文档、工具、库或社区。负责交付它的 Apple 团队于 2016 年正式解散并重新分配/解雇,整个 macOS 自动化平台自 10.13 以来一直处于维护模式(并且已经烂尾了!)。在经历了 25 年的持续忽视、管理不善和搞砸之后,无需专家就能猜出 Apple 遗留的、仅限 Mac 的自动化技术现在将走向何方。

CocoaScript 有效……仅此而已。它是第三方开源软件,因此至少它不依赖 Apple 的持续开发和支持,但它从未发展出足够庞大和充满活力的用户社区,使其获得广泛的成功。快速浏览一下 GitHub 上的 CocoaScript/Mocha 项目同样表明除了基本维护之外没有正在进行的开发。

这并不是说您不能使用它们[...暂时],但除非您有无可避免的令人信服的理由这样做,否则只有一个现在重要的 JS 平台:Node.js.

与上述不同,Node 享有巨大的全球投资、开发、工具、文档、社区和市场增长。 (2016 年有 350 万用户并且还在增长!)完全开源和独立。几乎可以在所有重要的操作系统平台上运行:Windows、Mac、Linux;甚至安卓。 NPM 也是一种非凡的资源:使用 PyPI、RubyGems 等轻松实现。 (甚至还有用于 Cocoa 和 Apple 活动的 macOS 库,尽管由于 Apple 日益混乱的平台的所有影响和不确定性,现在两者可能都需要一些 TLC。)哦,还有大量的工作和 FOSS 项目机会,如果你有朝一日希望成为专业人士也是。

HTH


附言要回答您的原始问题,请使用 -[NSFileHandle fileHandleWithStandardOutput] 获取到 stdout 的管道,并根据需要多次调用其 -writeData: 方法,传递(例如)通过 [[NSString stringWithString: aMessage] dataUsingEncoding: NSUTF8StringEncoding] 创建的 NSData 实例作为它的参数。或者,你知道,只是忽略所有这些并节点它! ;)

/relurk

【讨论】:

  • 所以如果我想使用节点代替我会安装node,然后将脚本传递给node而不是osascriptnode 是否预装在 OSX 上?如果没有,将来有可能预装吗?
  • 仅供参考,我不明白您在答案中的代码。这是 Obj-C?
  • 1.是的,在终端中输入 node 以启动交互式会话,或在终端中输入 node yourscript.js 在终端中运行 JS 脚本,或者在脚本文件的顶部添加 #!/usr/bin/env node 并添加 chmod +x yourscript.js 以使其可执行。 2. 它不是预装的,也不太可能是因为苹果没有(也不能)控制它;但是,自己安装它是微不足道的(标准的点击式 macOS pkg 安装程序)并且回报是巨大的。
  • 要在 JavaScript/Python/Lua/etc 中使用 Cocoa,您必须自己学习如何将其文档翻译成原生语法; Cocoa API 非常庞大,Apple 仅为 ObjC 和 Swift 用户编写其文档和示例代码。每个桥将 ObjC 功能和方法名称映射到您自己的语言略有不同,因此也要学习桥自己的文档。 p.s.对于认真的 Cocoa 开发,最好吸干它并学习 Swift:该语言是一团糟,它的 Cocoa 桥和其他语言一样繁琐,但它是保证享受 Apple 大量投资和支持的唯一选择.
【解决方案2】:

脚本是一个表达式,计算结果为最终值,从 JSContext 返回给调用者。

如果您希望该值由重复或多行组成,那么这就是您的脚本需要定义和返回的值。

(() => {

    // enumFromToInt :: Int -> Int -> [Int]
    const enumFromToInt = (m, n) =>
        n >= m ? Array.from({
            length: Math.floor(n - m) + 1
        }, (_, i) => m + i) : [];

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    return unlines(
        enumFromToInt(1, 25)
        .map(n => n.toString() + " hello")
    );
})()

【讨论】:

    猜你喜欢
    • 2015-01-05
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多