119

我在 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
4

7 回答 7

181

文档中:

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
于 2013-09-10T20:31:22.150 回答
44

对我来说,我更喜欢使用 `` 来调用 shell 命令并检查 $? 获取进程状态。美元?是一个进程状态对象,可以从这个对象中获取命令的进程信息,包括:状态码、执行状态、pid等。

$ 的一些有用方法?目的:

   $?.exitstatus => return error code    
   $?.success? => return true if error code is 0, otherwise false
   $?.pid => created process pid
于 2016-07-31T11:17:15.337 回答
31

systemfalse如果命令具有非零退出代码,或者nil没有命令,则返回。

所以

system( "foo" ) or exit

或者

system( "foo" ) or raise "Something went wrong with foo"

应该可以工作,并且相当简洁。

于 2013-09-10T20:26:44.280 回答
6

您没有捕获system调用的结果,这是返回结果代码的位置:

exit_code = system("ruby test.rb")

请记住,每个system调用或等效调用(包括反引号方法)都会生成一个新的 shell,因此无法捕获先前 shell 环境的结果。在这种情况下exit_codetrue如果一切顺利,nil否则。

popen3命令提供了更多低级详细信息。

于 2013-09-10T20:26:59.537 回答
6

一种方法是使用and或链接它们&&

system("VBoxManage createvm --name test1") and system("ruby test.rb")

如果第一个调用失败,则不会运行第二个调用。

您可以将它们包装在 anif ()中以提供一些流量控制:

if (
  system("VBoxManage createvm --name test1") && 
  system("ruby test.rb")
) 
  # do something
else
  # do something with $?
end
于 2013-09-10T21:43:58.410 回答
1

我想要类似的东西

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)

您还可以为嘈杂的程序抑制标准输出和标准错误:

sys("hg", "update", "default", :out => File::NULL, :err => File::NULL)
于 2021-04-25T10:44:55.713 回答
1

Ruby 2.6 添加了在 Kernel#system 中引发异常的选项

system("command", exception: true)
于 2021-11-30T16:26:33.563 回答