【问题标题】:ruby system command check exit coderuby 系统命令检查退出代码
【发布时间】: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

【问题讨论】:

标签: ruby command exit exit-code


【解决方案1】:

来自documentation

如果命令给出零退出状态,系统返回truefalse 非零退出状态。如果命令执行失败,则返回 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)&gt; system("touch /root/test 2&gt; /dev/null") =&gt; false [11] pry(main)&gt; $?.exitstatus =&gt; 0 [12] pry(main)&gt; system("touch /root/test 2&gt; /dev/null"); $?.exitstatus =&gt; 1
  • 此处提供了system、反引号、%xexec 的另一个出色比较:stackoverflow.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_codetrue,如果一切正常,则 nil 否则。

    popen3 命令提供更多底层细节。

    【讨论】:

    【解决方案5】:

    一种方法是使用and&amp;&amp; 链接它们:

    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)
      

      【讨论】:

        猜你喜欢
        • 2019-01-26
        • 2012-03-24
        • 1970-01-01
        • 1970-01-01
        • 2017-12-02
        • 1970-01-01
        • 2010-12-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多