Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 为什么Open3.popen3在缺少可执行文件时返回错误错误?_Ruby_Popen3 - Fatal编程技术网

Ruby 为什么Open3.popen3在缺少可执行文件时返回错误错误?

Ruby 为什么Open3.popen3在缺少可执行文件时返回错误错误?,ruby,popen3,Ruby,Popen3,我正在围绕CLI制作一个Ruby包装器。我发现了一个简洁的方法,Open3.capture3(它在内部使用Open3.popen3),它允许我执行命令并捕获stdout、stderr和exit代码 我想检测的一件事是,如果找不到CLI可执行文件(并为此引发一个特殊错误)。我知道当找不到命令时,unixshell会给出退出代码127。 当我在bash中执行$foo时,会得到-bash:foo:command not found,这正是我想要显示的错误消息 考虑到这些,我编写了如下代码: requi

我正在围绕CLI制作一个Ruby包装器。我发现了一个简洁的方法,
Open3.capture3
(它在内部使用
Open3.popen3
),它允许我执行命令并捕获stdout、stderr和exit代码

我想检测的一件事是,如果找不到CLI可执行文件(并为此引发一个特殊错误)。我知道当找不到命令时,unixshell会给出退出代码
127
。 当我在bash中执行
$foo
时,会得到
-bash:foo:command not found
,这正是我想要显示的错误消息

考虑到这些,我编写了如下代码:

require "open3"

stdout, stderr, status = Open3.capture3(command)
case status.exitstatus
when 0
  return stdout
when 1, 127
  raise MyError, stderr
end
但是,当我使用
command=“foo”
运行它时,我得到一个错误:

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'

为什么会发生这种错误?我以为
Open3.capture3
应该直接在shell中执行该命令,那么为什么我不得到一个正常的STDERR和退出代码
127

Open3.popen3
委托给
内核.spawn
,它根据命令传入的方式将命令发送给shell或直接发送给操作系统

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[0] and zero or more arguments (no shell)
我们可能期望,如果调用
Kernel.spawn(“foo”)
,它将被传递到shell(而不是操作系统)。但事实并非如此,
Kernel.exec
的文档解释了原因:

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).
最后一段揭示了解决方案

require "open3"

stdout, stderr, status = Open3.capture3(command + ";")
case status.exitstatus
when 0
  return stdout
when 1, 127
  raise MyError, stderr
end

旧但有效。我的添加如果您想添加参数,请将它们包括在命令中,例如,
Open3.capture3('ld--version'+';')
,如果您想这样添加,它将不起作用
Open3.capture3('ld','--version'+';'))
,这是添加参数的推荐方法。