Raise exception on shell command failure?

2020-06-16 10:58发布

问题:

I'm writing some scripts in Ruby, and I need to interface with some non-Ruby code via shell commands. I know there are at least 6 different ways of executing shell commands from Ruby, unfortunately, none of these seem to stop execution when a shell command fails.

Basically, I'm looking for something that does the equivalent of:

set -o errexit

...in a Bash script. Ideally, the solution would raise an exception when the command fails (i.e., by checking for a non-zero return value), maybe with stderr as a message. This wouldn't be too hard to write, but it seems like this should exist already. Is there an option that I'm just not finding?

回答1:

Easiest way would be to create a new function (or redefine an existing one) to call system() and check the error code.

Something like:

old_sys = system

def system(...)
  old_system(...)
  if $? != 0 then raise :some_exception
end

This should do what you want.



回答2:

You can use one of ruby's special variables. The $? (analogous to the same shell script var).

`ls`
if $?.to_s == "0"
  # Ok to go
else
  # Not ok
end

Almost every program sets this var to 0 if everything went fine.



回答3:

Tiny bit simpler: you don't need to check $? w/ system, and since the command you ran will output to stderr itself you can usually just non-zero-exit rather than raising an exception w/ an ugly stack-trace:

system("<command>") || exit(1)

So you could take that a step further and do:

(system("<command 1>") &&
  system("<command 2>") &&
  system("<command 3>")) || exit(1)

...which would short-circuit and fail on error (in addition to being hard to read).

Ref: From Ruby 2.0 doc for system (although true of 1.8.7 as well):

system returns true if the command gives zero exit status, false for non zero exit status.

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



回答4:

Ruby 2.6 adds an exception: argument:

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