ruby 系统命令检查退出代码
Posted
技术标签:
【中文标题】ruby 系统命令检查退出代码【英文标题】:ruby system command check exit code 【发布时间】:2013-09-14 16:52:40 【问题描述】:我在 ruby 中有一堆系统调用,如下所示,我想同时检查它们的退出代码,以便在该命令失败时退出我的脚本。
system("VBoxManage createvm --name test1")
system("ruby test.rb")
我想要类似的东西
system("VBoxManage createvm --name test1", 0)
这可能吗?
我已经尝试过类似的方法,但也没有用。
system("ruby test.rb")
system("echo $?")
或
`ruby test.rb`
exit_code = `echo $?`
if exit_code != 0
raise 'Exit code is not zero'
end
【问题讨论】:
Catching command-line errors using %x 的可能重复项 在上面的例子中,exit_code
将是一个字符串——"0\n"
或"1\n"
,所以exit_code != 0
将永远为真
【参考方案1】:
来自documentation:
如果命令给出零退出状态,系统返回
true
,false
非零退出状态。如果命令执行失败,则返回nil
。
system("unknown command") #=> nil
system("echo foo") #=> true
system("echo foo | grep bar") #=> false
还有
$?
中有错误状态。
system("VBoxManage createvm --invalid-option")
$? #=> #<Process::Status: pid 9926 exit 2>
$?.exitstatus #=> 2
【讨论】:
以及如何将其输出(不是退出代码)捕获到变量中? 如果您在 Rails 控制台中进行测试,请记住您可能会丢失 $?所以你需要将它作为你的 REPL 命令的一部分来捕获[10] pry(main)> system("touch /root/test 2> /dev/null") => false [11] pry(main)> $?.exitstatus => 0 [12] pry(main)> system("touch /root/test 2> /dev/null"); $?.exitstatus => 1
此处提供了system
、反引号、%x
和 exec
的另一个出色比较:***.com/questions/6338908/…【参考方案2】:
对我来说,我更喜欢使用 `` 来调用 shell 命令并检查 $?获取进程状态。美元?是一个进程状态对象,可以从这个对象中获取命令的进程信息,包括:状态码、执行状态、pid等。
$ 的一些有用方法?对象:
$?.exitstatus => return error code
$?.success? => return true if error code is 0, otherwise false
$?.pid => created process pid
【讨论】:
在 Rubocop 的帮助下,我发现$?
的可读别名是$CHILD_STATUS
【参考方案3】:
system
如果命令具有非零退出代码,则返回 false
,如果没有命令,则返回 nil
。
因此
system( "foo" ) or exit
或
system( "foo" ) or raise "Something went wrong with foo"
应该可以工作,并且相当简洁。
【讨论】:
【参考方案4】:您没有捕获 system
调用的结果,这是返回结果代码的位置:
exit_code = system("ruby test.rb")
记住每个 system
调用或等效调用(包括反引号方法)都会生成一个新的 shell,因此无法捕获前一个 shell 环境的结果。在这种情况下,exit_code
是 true
,如果一切正常,则 nil
否则。
popen3
命令提供更多底层细节。
【讨论】:
Open3.capture3
是一种特别容易用于此类任务的方法。【参考方案5】:
一种方法是使用and
或&&
链接它们:
system("VBoxManage createvm --name test1") and system("ruby test.rb")
如果第一个调用失败,则不会运行第二个调用。
您可以将它们包装在 if ()
中以提供一些流量控制:
if (
system("VBoxManage createvm --name test1") &&
system("ruby test.rb")
)
# do something
else
# do something with $?
end
【讨论】:
这是目前为止我想要达到的目标,简单明了。谢谢【参考方案6】:我想要类似的东西
system("VBoxManage createvm --name test1", 0)
您可以将 exception: true
添加到您的 system
调用中,以在非 0 退出代码上引发错误。
例如,考虑system
周围的这个小包装器,它打印命令(类似于bash -x
,如果退出代码非0(如bash -e
)则失败并返回实际退出代码:
def sys(cmd, *args, **kwargs)
puts("\e[1m\e[33m#cmd #args\e[0m\e[22m")
system(cmd, *args, exception: true, **kwargs)
return $?.exitstatus
end
被称为:sys("hg", "update")
如果你想调用一个对退出代码使用不同约定的程序,你可以禁止引发异常:
sys("robocopy", src, dst, "/COPYALL", "/E", "/R:0", "/DCOPY:T", exception: false)
您还可以为嘈杂的程序抑制 stdout 和 stderr:
sys("hg", "update", "default", :out => File::NULL, :err => File::NULL)
【讨论】:
【参考方案7】:Ruby 2.6 added option to raise exception in Kernel#system:
system("command", exception: true)
【讨论】:
以上是关于ruby 系统命令检查退出代码的主要内容,如果未能解决你的问题,请参考以下文章