Dhrubo_moy Dhrubo_moy - 3 months ago 27
Ruby Question

Open3.popen3 returns wrong error Errno::ENOENT on Windows

I have following piece of code in a test.rb file:

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
is a console application that I created, located in the
C:\Program Files\foo\
directory. It works like following:


  • When I run
    foo.exe
    it outputs
    "Hello world!"

  • When I run
    foo.exe
    with any argument (eg.
    foo.exe /blah
    ), it outputs a help message.



When I run
ruby test.rb
I am getting the following error:

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>'


If I change the code in test.rb to call the
popen3
method like this:
Open3.popen3(cmd, '')
, I don't get the
Errno::ENOENT
error, instead I am getting the help message. But I want the
"Hello World"
output.

This is a strange behavior. I have searched for a solution but nothing is working including this answer.
My question is why am I getting this error and how to solve it?

Answer

You are having trouble because "Program Files" is a folder with a space in it. Whenever that happens, you need to double quote it, just as you would on a cmd.exe prompt. And when you're double-quoting, you must remember that your backslash character "\" is an escape character, so you have to double-backslash to get the proper folder separators for Windows. I'm going to use code which actually returns something in my environment; adjust it to your taste. So your code should look like:

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

If you have command line parameters to pass to git, you'd do it like this:

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
Comments