如何包含使用 FileUtils#sh 执行命令的管道



我知道足够多的Ruby是危险的,所以我正在编写一堆构建自动化脚本作为Rake任务,主要是通过API文档中的示例进行操作。

我正在使用如下代码编写一堆构建命令的脚本:

results = {}
schemes.each { |scheme|
    command = "xcodebuild", "-scheme", scheme
    if options.configuration
        command.push "-configuration", options.configuration
    end
    command.push "archive"
    sh *command do |ok, res|
        results[scheme] = ok
    end
}

这工作正常,但会将大量输出转储到控制台,这有点妨碍了。所以我很想通过 xcpretty 来重新格式化它。

如果我实际上从我的终端运行命令,它工作正常:

xcodebuild -scheme Foo -configuration Release archive | xcpretty

但是,如果我修改 Rake 任务以仅将这些部分附加到命令数组的末尾,sh认为它们是xcodebuild的参数。

    command.push "archive", "|", "xcpretty"

我已经看到许多示例将sh与字符串形式的管道一起使用,但不是数组形式。由于我正在构建的命令的性质(可选参数、带空格的参数和其他字符),数组形式处理起来要干净得多。但是有没有办法在使用时包括输出管道?

一个好的解决方案是使用 Open3,这是 Ruby 的标准部分,它有很多用于打开进程和安排管道的实用程序。

这是一个对我有用的例子:

require 'open3'
Open3.pipeline(['ls', '-l'], ['grep', 'z'])

运行此操作时,管道中最后一个命令的标准输出管道将连接到 Ruby 进程的预先存在的标准输出管道。 这意味着您将能够在生成任何输出时立即看到它,而不是等待流程结束。 此方法的另一个好处是它不会生成外壳;它只是直接生成进程。

另一种选择是简单地使用 Array#join 将参数与空格连接在一起,然后再将它们传递给 sh 。 你只需要注意你的论点可能有空格的可能性,如果是这样,那么你必须正确地引用或转义它们。 此方法将生成一个 shell 来处理您的命令,它还应该为长时间运行的进程提供即时输出。

最新更新