Open3.popen3 returns 错误 Errno::ENOENT on Windows
Open3.popen3 returns wrong error Errno::ENOENT on Windows
我在test.rb中有以下代码:
require 'open3'
cmd = 'C:\Program Files\foo\bar.exe'
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
puts "stdout: #{stdout.read}"
puts "\n\n"
puts "stderr: #{stderr.read}"
end
bar.exe
是我创建的控制台应用程序,位于 C:\Program Files\foo\
。当我 运行 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 Files\foo\bar.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"
输出。
我搜索了解决方案,但没有任何效果,包括“Why does Open3.popen3 return wrong error when executable is missing?”的答案。
为什么会出现此错误,我该如何解决?
您遇到问题是因为 "Program Files" 是一个包含 space 的文件夹。每当发生这种情况时,您都需要将其双引号,就像在 cmd.exe 提示符下一样。当你使用双引号时,你必须记住你的反斜杠字符“\”是一个转义字符,所以你必须使用双反斜杠以获得 Windows 的正确文件夹分隔符。我将使用在我的环境中实际上 returns 某些东西的代码;根据你的口味调整它。所以你的代码应该是这样的:
require 'open3'
cmd = "\"C:\Program Files\Git\bin\git.exe\""
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
puts "stdout: #{stdout.read}"
puts "\n\n"
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 "\n\n"
puts "stderr: #{stderr.read}"
end
对此进行冥想:
cmd = "\P\f\b"
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 = '\P\f\b'
cmd.size # => 6
cmd.chars # => ["\", "P", "\", "f", "\", "b"]
cmd.chars.map(&:ord) # => [92, 80, 92, 102, 92, 98]
与第一个示例一样,您正在使用带有单反斜杠的双引号字符串作为 path/directory 分隔符。单个反斜杠 \f
和 \b
是双引号字符串中的转义字符,无法识别,因为它们是使用 \ f 或 \ b.
你有两种方法来处理这个问题,要么像第二个例子那样转义反斜杠,要么像第三个例子那样使用单引号字符串。使用第二种方式被认为是混乱的,所以使用最后一种方式以获得可读性和更容易维护。您将获得相同的字符,但视觉噪音更少。这适用于大多数语言中的字符串使用。
要知道的第二件事是 Ruby 不需要反斜杠作为路径分隔符。 IO documentation 表示:
Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename "/gumby/ruby/test.rb"
will be opened as "\gumby\ruby\test.rb"
. When specifying a Windows-style filename in a Ruby string, remember to escape the backslashes:
"c:\gumby\ruby\test.rb"
Our examples here will use the Unix-style forward slashes; File::ALT_SEPARATOR can be used to get the platform-specific separator character.
最后,您应该查看 STDLib 中的 Ruby 的 Shell and Shellwords。他们是你的朋友。
使用 Open3.popen3([bin, bin])
来防止 shell 命令处理 popen3
的单个参数(以及 spawn
等相关方法)。
如您所见,可以正常传递多个参数而无需调用 shell(例如
Open3.popen3(bin, arg1, arg2)
).
我在test.rb中有以下代码:
require 'open3'
cmd = 'C:\Program Files\foo\bar.exe'
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
puts "stdout: #{stdout.read}"
puts "\n\n"
puts "stderr: #{stderr.read}"
end
bar.exe
是我创建的控制台应用程序,位于 C:\Program Files\foo\
。当我 运行 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 Files\foo\bar.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"
输出。
我搜索了解决方案,但没有任何效果,包括“Why does Open3.popen3 return wrong error when executable is missing?”的答案。
为什么会出现此错误,我该如何解决?
您遇到问题是因为 "Program Files" 是一个包含 space 的文件夹。每当发生这种情况时,您都需要将其双引号,就像在 cmd.exe 提示符下一样。当你使用双引号时,你必须记住你的反斜杠字符“\”是一个转义字符,所以你必须使用双反斜杠以获得 Windows 的正确文件夹分隔符。我将使用在我的环境中实际上 returns 某些东西的代码;根据你的口味调整它。所以你的代码应该是这样的:
require 'open3'
cmd = "\"C:\Program Files\Git\bin\git.exe\""
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
puts "stdout: #{stdout.read}"
puts "\n\n"
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 "\n\n"
puts "stderr: #{stderr.read}"
end
对此进行冥想:
cmd = "\P\f\b"
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 = '\P\f\b'
cmd.size # => 6
cmd.chars # => ["\", "P", "\", "f", "\", "b"]
cmd.chars.map(&:ord) # => [92, 80, 92, 102, 92, 98]
与第一个示例一样,您正在使用带有单反斜杠的双引号字符串作为 path/directory 分隔符。单个反斜杠 \f
和 \b
是双引号字符串中的转义字符,无法识别,因为它们是使用 \ f 或 \ b.
你有两种方法来处理这个问题,要么像第二个例子那样转义反斜杠,要么像第三个例子那样使用单引号字符串。使用第二种方式被认为是混乱的,所以使用最后一种方式以获得可读性和更容易维护。您将获得相同的字符,但视觉噪音更少。这适用于大多数语言中的字符串使用。
要知道的第二件事是 Ruby 不需要反斜杠作为路径分隔符。 IO documentation 表示:
Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename
"/gumby/ruby/test.rb"
will be opened as"\gumby\ruby\test.rb"
. When specifying a Windows-style filename in a Ruby string, remember to escape the backslashes:
"c:\gumby\ruby\test.rb"
Our examples here will use the Unix-style forward slashes; File::ALT_SEPARATOR can be used to get the platform-specific separator character.
最后,您应该查看 STDLib 中的 Ruby 的 Shell and Shellwords。他们是你的朋友。
使用 Open3.popen3([bin, bin])
来防止 shell 命令处理 popen3
的单个参数(以及 spawn
等相关方法)。
如您所见,可以正常传递多个参数而无需调用 shell(例如
Open3.popen3(bin, arg1, arg2)
).