Open3.popen3在Windows上返回错误Errno:: enent



我在test.rb中有以下代码:

require 'open3'
cmd = 'C:Program Filesfoobar.exe'
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  puts "stdout: #{stdout.read}"
  puts "nn"
  puts "stderr: #{stderr.read}"
end

bar.exe是我创建的控制台应用程序,位于C:Program Filesfoo中。当我运行bar.exe:

  • 输出"Hello world!"
  • 与任何参数,如bar.exe /blah,它输出帮助消息。

当我运行ruby test.rb,我得到这个错误:

C:RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/open3.rb:193:in 'spawn': No such file or directory - C:Program Filesfoobar.exe (Errno::ENOENT)
from C:RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/open3.rb:193:in 'popen_run'
from C:RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/open3.rb:193:in 'popen3'
from test.rb:3:in '<main>'

如果我将代码改为调用popen3:

Open3.popen3(cmd, '')

我没有得到Errno::ENOENT错误,而是得到帮助消息,但我想要"Hello World"输出。

我搜索了一个解决方案,但没有任何工作,包括"为什么Open3。.

为什么我得到这个错误,我如何解决它?

思考一下:

cmd = "Pfb"
cmd.size             # => 3
cmd.chars            # => ["P", "f", "b"]
cmd.chars.map(&:ord) # => [80, 12, 8]
cmd = "\P\f\b"
cmd.size             # => 6
cmd.chars            # => ["\", "P", "\", "f", "\", "b"]
cmd.chars.map(&:ord) # => [92, 80, 92, 102, 92, 98]
cmd = 'Pfb'
cmd.size             # => 6
cmd.chars            # => ["\", "P", "\", "f", "\", "b"]
cmd.chars.map(&:ord) # => [92, 80, 92, 102, 92, 98]

与第一个示例一样,您使用双引号字符串和单个反斜杠作为路径/目录分隔符。单个反斜杠fb是双引号字符串中的转义字符,由于使用fb键入,因此无法识别。

有两种方法可以处理这个问题,或者像第二个示例那样转义反斜杠,或者像第三个示例那样使用单引号字符串。使用第二种方法被认为是混乱的,所以使用最后一种方法来提高可读性和更容易维护。你会得到相同的字符,但视觉噪音更少。这适用于大多数语言中的字符串使用。

要知道的第二件事是Ruby不需要反斜杠作为路径分隔符。IO文档说:

如果可能的话,Ruby将在不同的操作系统约定之间转换路径名。例如,在Windows系统上,文件名"/gumby/ruby/test.rb"将被打开为"gumbyrubytest.rb"。当在Ruby字符串中指定windows样式的文件名时,请记住转义反斜杠:

"c:\gumby\ruby\test.rb"

我们这里的例子将使用unix风格的正斜杠;File::ALT_SEPARATOR可用于获取特定于平台的分隔符。

最后,您应该查看STDLib中的Ruby Shell和Shellwords。他们是你的朋友。

您遇到麻烦了,因为"Program Files"是一个带有空格的文件夹。无论何时发生这种情况,都需要双引号,就像在cmd.exe提示符上一样。当你使用双引号时,你必须记住你的反斜杠字符""是一个转义字符,所以你必须使用双反斜杠来获得正确的Windows文件夹分隔符。我将使用在我的环境中返回一些东西的代码;根据你的口味调整。所以你的代码应该是这样的:

require 'open3'
cmd = ""C:\Program Files\Git\bin\git.exe""
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  puts "stdout: #{stdout.read}"
  puts "nn"
  puts "stderr: #{stderr.read}"
end

如果你有命令行参数要传递给git,你可以这样做:

require 'open3'
cmd = ""C:\Program Files\Git\bin\git.exe" --version"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  puts "stdout: #{stdout.read}"
  puts "nn"
  puts "stderr: #{stderr.read}"
end

使用Open3.popen3([bin, bin])来防止shell命令处理popen3(以及spawn等相关方法)的单个参数。

正如你所注意到的,多个参数可以在不调用shell的情况下正常传递。Open3.popen3(bin, arg1, arg2))。

相关内容

最新更新