【问题标题】:Why does Open3.popen3 return wrong error when executable is missing?为什么缺少可执行文件时 Open3.popen3 会返回错误错误?
【发布时间】:2014-11-20 07:47:58
【问题描述】:

我正在围绕 CLI 制作一个 Ruby 包装器。我发现了一个简洁的方法Open3.capture3(内部使用Open3.popen3),它可以让我执行命令并捕获标准输出、标准错误和退出代码。

我想要检测的一件事是是否找不到 CLI 可执行文件(并为此引发一个特殊错误)。我知道 UNIX shell 在找不到命令时会给出退出代码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

【问题讨论】:

    标签: ruby popen3


    【解决方案1】:

    Open3.popen3 委托给Kernel.spawn,这取决于传递命令的方式,将命令提供给 shell 或直接提供给 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[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' + ';')这是添加参数的推荐方式。
    猜你喜欢
    • 2016-12-25
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 2013-04-27
    • 1970-01-01
    相关资源
    最近更新 更多