【发布时间】:2013-07-29 17:42:25
【问题描述】:
我正在使用 Frank 进行 iOS 测试。它也是一种使用黄瓜的红宝石。我有一个“给定”步骤来检查应用程序是否正在运行或是否已崩溃。如果我的步骤发现它已经崩溃,我想再次启动该应用程序。我使用存储在黄瓜 .feature 文件附近某处的 shell 脚本启动应用程序。
如何从该步骤定义中调用脚本?
【问题讨论】:
标签: iphone ios ruby shell frank
我正在使用 Frank 进行 iOS 测试。它也是一种使用黄瓜的红宝石。我有一个“给定”步骤来检查应用程序是否正在运行或是否已崩溃。如果我的步骤发现它已经崩溃,我想再次启动该应用程序。我使用存储在黄瓜 .feature 文件附近某处的 shell 脚本启动应用程序。
如何从该步骤定义中调用脚本?
【问题讨论】:
标签: iphone ios ruby shell frank
你可以通过几种不同的方式做到这一点
Kernel.system "command"
%x[command]
`command`
【讨论】:
Kernel.;默认情况下,该模块已包含在 Object 中。或类似的东西。
Kernel 前缀是多余的,但它与查找文档相关。那些随处可见的神奇方法,通常都在 Kernel 中。
正如其他答案所建议的那样,有很多方法可以从 Ruby 执行 shell 脚本,但它们的创建方式并不相同。我将尝试更详细地解释我所知道的所有方法。
`command arg1 arg2`
%x(command arg1 arg2)
在子 shell 中运行命令并返回命令的输出。命令及其参数以反引号分隔的字符串形式提供。另一种语法是%x(...),用于避免转义问题,例如当您要执行包含反引号的命令时。括号可以替换为其他分隔符,例如[]、{}、!!,......以便能够解决任何转义问题。
Stderr 正常打印,Stdout 被抑制。返回命令的标准输出。这意味着您可以使用反引号将命令的输出放入变量中以供进一步处理。
exec("command arg1 arg2")
exec("command", "arg1", "arg2")
通过运行命令替换当前进程。命令及其参数以普通字符串或以逗号分隔的字符串列表的形式提供。如果您已经有一个参数列表作为数组,这可能会很有用。输出保持原样,即会像直接运行命令一样打印到控制台。
system("command arg1 arg2")
system("command","arg1 arg2")
类似于Kernel.exec,但再次在子shell 中运行。如果进程正确退出(状态 0),则返回 true,否则返回 false。这在if-statements 中很有效。
pid = spawn("command")
# do other stuff
Process.wait(pid)
类似于Kernel.system,但会产生一个子进程来运行指定的命令。因此,除非使用Process.wait,否则父进程不会等待命令完成执行。返回值是衍生进程的 PID。
io = IO.popen("command")
IO.popen("command") {|io| ... }
再次在子进程中运行命令,但允许对 IO 进行更大的控制。子进程的 stdout 和 stdin 连接到一个 IO 对象,该对象可以作为返回值或块参数访问。如果通过返回值获取,IO对象在使用io.close后需要关闭。
【讨论】:
对于比system 或IO.popen 更高级的用例,您可以使用Ruby 标准库中的Open3。它的popen3 方法允许您手动与子进程的标准输入、标准输出和标准错误进行交互。 Open3 的 popen2 方法是一样的,只是它没有给你 stderr。一个使用popen2的例子:
require 'open3'
Open3.popen2("wc -c") do |stdin, stdout, status_thread|
stdin.print "answer to life the universe and everything"
stdin.close
p stdout.gets #=> "42\n"
end
【讨论】:
Here are some nice ways。反引号可能是侵入性最小的。但请注意:正如 tadman 所指出的,exec 会终止调用进程,这可以通过创建子进程或使用 system 来避免。
【讨论】:
exec 有效地终止了调用进程,因此您永远不会得到响应,因此它可能是该列表中的最后一个。为什么它最“可读”?