当shelled-out命令返回非零退出代码时,如何让Ruby脚本失败?

时间:2015-06-19 12:53:51

标签: ruby command-line-interface

在Ruby脚本中,有various ways来调用系统命令/命令行

  1. 反叛:`command arg1 arg2`
  2. 分隔形式,例如%x(command arg1 arg2)(可提供其他分隔符)
  3. Kernel#system方法:system('command arg1 arg2')
  4. Kernel#exec方法:exec('command arg1 arg2')
  5. 如果我希望当一个被调用的命令失败(带有非零退出代码)时Ruby脚本失败(有异常),我可以检查第一个特殊变量$?中的退出代码两种变体:

    `command arg1 arg2`
    fail unless $? == 0
    

    %x,command arg1 arg2,
    fail unless $? == 0
    

    如果我使用命令的标准输出转到Ruby脚本的标准输出(我是),我可以使用变量3并检查其返回值:

    unless system('command arg1 arg2')
      fail
    end
    

    如果我不关心拯救异常的能力,也不关心无法解决的异常的堆栈跟踪打印行为,我当然可以使用exit(1)或前两个变体exit($?) fail的地方。

    如果进一步执行命令是Ruby脚本应该做的最后一件事,即使命令成功(退出代码0),我也可以使用第四个变体:

    exec('command arg1 arg2')
    

    这将使用通过调用命令创建的新进程替换Ruby进程,但Ruby脚本的调用者的效果将是相同的:如果被调用的命令导致非正常,则他会看到非零退出代码 - 零退出代码。

    我非常喜欢第四个变体的简洁性,但是如果执行命令不是最后要做的事情,那么我很遗憾不会使用它。相比之下,其他变体的条件failexit调用看起来非常不洁净,并且在我的一个用例中经常违反单一抽象级别和单一责任原则。

    我当然可以轻松地为前三种方法中的任何一种编写一个包装函数,使它们的用法看起来简洁,但因为这看起来像是一个基本的操作方法,我想知道Ruby是否已经有类似的东西内置的 ...无论是我可以使用的实用程序函数,而不是我自己的包装器,或者是一种机制,它会改变一个或多个命令调用方法的行为以导致错误或非命令失败时退出零,类似于' s option to set -e

1 个答案:

答案 0 :(得分:4)

据我所知,没有内置的方法可以做到这一点,但你几乎可以用一点元编程魔法来获得你想要的行为

def set_exit enable
  if enable
    define_method :system do |*args|
      Kernel.system *args
      exit $?.exitstatus unless $?.success?
    end
  else
    define_method :system, Kernel.instance_method(:system)
  end
end

set_exit true
# ...
# any failed system calls here will cause your script to exit
# ...
set_exit false
# now system is back to normal

这可以通过为system重新定义Object,同时在需要内置行为时明确使用Kernel.system