提高shell命令失败的异常?

Ben*_*kes 7 ruby shell exception

我正在用Ruby编写一些脚本,我需要通过shell命令与一些非Ruby代码进行交互.我知道从Ruby执行shell命令至少有6种不同的方法,遗憾的是,当shell命令失败时,这些方法似乎都没有停止执行.

基本上,我正在寻找相当于以下内容的东西:

set -o errexit
Run Code Online (Sandbox Code Playgroud)

...在Bash脚本中.理想情况下,解决方案会在命令失败时(即通过检查非零返回值)引发异常,可能使用stderr作为消息.这不会太难写,但似乎这应该存在.我有没有找到一个选项?

Ben*_*kes 10

Ruby 2.6 添加了一个exception:参数

system('ctat nonexistent.txt', exception: true) # Errno::ENOENT (No such file or directory - ctat)
Run Code Online (Sandbox Code Playgroud)


use*_*044 9

最简单的方法是创建一个新函数(或重新定义现有函数)来调用system()并检查错误代码.

就像是:

old_sys = system

def system(...)
  old_system(...)
  if $? != 0 then raise :some_exception
end
Run Code Online (Sandbox Code Playgroud)

这应该做你想要的.

  • 是的,当我说"写起来不会太难"时,这就是我的想法,但它看起来似乎应该已经解决了,你知道吗?谢谢你的例子. (2认同)

Tom*_*art 7

你可以使用ruby的一个特殊变量.$?(类似于相同的shell脚本var).

`ls`
if $?.to_s == "0"
  # Ok to go
else
  # Not ok
end
Run Code Online (Sandbox Code Playgroud)

如果一切顺利的话,几乎每个程序都将此var设置为0.

  • 你为什么要用`to_s`来比较字符串'0`?`如果$?== 0` (6认同)
  • 最好的检查方法是`if $?.success?`https://ruby-doc.org/core-2.2.0/Process/Status.html#method-i-success-3F.我使用它的方式是`exit $?.to_i,除非$?成功?` (2认同)

Ben*_*avi 7

稍微简单一点:你不需要检查$?w/system,并且因为你运行的命令将输出到stderr它自己,你通常可以只是非零退出而不是提出一个丑陋的堆栈跟踪异常:

system("<command>") || exit(1)
Run Code Online (Sandbox Code Playgroud)

所以你可以更进一步,做到:

(system("<command 1>") &&
  system("<command 2>") &&
  system("<command 3>")) || exit(1)
Run Code Online (Sandbox Code Playgroud)

......会出现短路并导致错误失败(除了难以阅读之外).

参考:从Ruby 2.0 doc system(虽然也是1.8.7):

true如果命令给出零退出状态,则系统返回false非零退出状态.

http://www.ruby-doc.org/core-2.0.0/Kernel.html#method-i-system