Why does Open3.popen3 return the wrong error when there is no executable file?
I am making a Ruby wrapper around the CLI. And I found a neat method
(which internally uses
) that allows me to execute commands and grab stdout, stderr and exit code.
One thing I want to detect is if the CLI executable is not found (and a special error is thrown for it). I know that UNIX shell gives exit code
when command was not found. And when I execute
in bash I get
-bash: foo: command not found
which is exactly the error message I want to display.
With all this in mind, I wrote the code like this:
require "open3" stdout, stderr, status = Open3.capture3(command) case status.exitstatus when 0 return stdout when 1, 127 raise MyError, stderr end
But, when I run it with
command = "foo"
, I get an error:
Errno::ENOENT: No such file or directory - foo /Users/janko/.rbenv/versions/2.1.3/lib/ruby/2.1.0/open3.rb:193:in `spawn' /Users/janko/.rbenv/versions/2.1.3/lib/ruby/2.1.0/open3.rb:193:in `popen_run' /Users/janko/.rbenv/versions/2.1.3/lib/ruby/2.1.0/open3.rb:93:in `popen3' /Users/janko/.rbenv/versions/2.1.3/lib/ruby/2.1.0/open3.rb:252:in `capture3'
Why is this error occurring? I thought I
had to execute this command directly in the shell, why don't I get a normal STDERR code and exit code
source to share
, which, depending on how the command is passed, pass the command to the shell or directly to the OS.
commandline : command line string which is passed to the standard shell cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.) [cmdname, argv0], arg1, ... : command name, argv and zero or more arguments (no shell)
We might expect that if we call it
, it will be passed to the shell (not the OS). But this is not the case, the documentation for
If the string from the first form (exec("command")) follows these simple rules: * no meta characters * no shell reserved word and no special built-in * Ruby invokes the command directly without shell You can force shell invocation by adding ";" to the string (because ";" is a meta character).
The last paragraph shows the solution.
require "open3" stdout, stderr, status = Open3.capture3(command + ";") case status.exitstatus when 0 return stdout when 1, 127 raise MyError, stderr end
source to share