2016-08-18 95 views
2

返回錯誤的錯誤errno的:: ENOENT我在test.rb以下代碼:Open3.popen3在Windows

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?」的答案。

爲什麼我得到這個錯誤,我該如何解決它?

+0

「C:/ Program Files/foo/bar.exe」是否可以替代? – tadman

回答

0

由於「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 "\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 
+0

工作就像一個魅力。非常感謝你! –

+1

請勿在路徑的雙引號字符串中使用轉義轉義。相反,做簡單的事情,讓Ruby找出路徑。 Ruby將自動正確地處理Windows上的正斜槓並正確轉換它們。有關更多信息,請參閱[IO文檔]的開頭部分(http://ruby-doc.org/core-2.3.1/IO.html)。 –

+0

我曾在25年前在BNR與一位綽號「The Tin Man」的人一起工作。那是你,你是約翰嗎? –

1

默想這樣的:

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] 

您正在使用帶有單反斜槓的雙引號字符串作爲路徑/目錄分隔符,如第一個示例中所示。單背削減\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.

最後,你應該看看Ruby的ShellShellwords在STDLIB。他們是你的朋友。

+0

非常感謝您的詳細解答。我先用單引號。但它沒有奏效。奇怪的行爲!跟隨傑伊·戈斯的建議,它的工作。 –

+0

逃離空間的建議是有效的。使用逃避反斜槓的建議只會導致噪音。 –

+0

我完全同意。奇怪的是'Open3.popen3('C:\ Program Files \ foo \ bar.exe')'在Open3.popen3(「\」C:\\ Program Files \\ foo \\ bar.exe \「」)'工作正常。 –

0

使用Open3.popen3([bin, bin])可防止將單個參數的shell命令處理爲popen3(以及相關方法,如spawn)。

正如您所注意到的,可以正常傳遞多個參數,而無需調用shell(例如, Open3.popen3(bin, arg1, arg2))。