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

das*_*s-g 6 ruby command-line-interface

在Ruby脚本中,有多种方法可以调用系统命令/命令行

  1. 反引号: `command arg1 arg2`
  2. 分隔形式,例如%x(command arg1 arg2)(可用的其他分隔符)
  3. Kernel#system 方法: system('command arg1 arg2')
  4. Kernel#exec 方法: exec('command arg1 arg2')

如果我希望Ruby脚本在被调用的命令失败时(异常)失败(使用非零退出代码),我可以检查$?前两个变量的特殊变量中的退出代码:

`command arg1 arg2`
fail unless $? == 0
Run Code Online (Sandbox Code Playgroud)

要么

%x,command arg1 arg2,
fail unless $? == 0
Run Code Online (Sandbox Code Playgroud)

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

unless system('command arg1 arg2')
  fail
end
Run Code Online (Sandbox Code Playgroud)

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

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

exec('command arg1 arg2')
Run Code Online (Sandbox Code Playgroud)

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

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

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

Max*_*Max 5

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

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
Run Code Online (Sandbox Code Playgroud)

这通过重新定义systemfor 来工作Object,同时Kernel.system在需要内置行为时显式使用。