Ruby: exceptions from popen vs popen3

218 views Asked by At

I'd like to know how to catch exceptions from Open3.popen3 on Ruby.

require "open3"
begin
  Open3.popen3("./somebinary") {|i,o,e,t|
#  IO.popen("./somebinary") {|i|
    $stderr.puts "popen"
    i.puts "some string"
  }
rescue StandardError => e
  $stderr.puts e.message
  $stderr.puts e.backtrace.inspect
  $stderr.puts "error"
  exit(1)
end

The problem is that the binary executable is of a wrong architecture and doesn't run on the local machine. When invoked from the command line, like so ./somebinary, you see the error message.

With popen, the error is caught by the rescue clause, but not with popen3.

If the rescue clause didn't have StandardError => e, the clause is entered, but you can't know the reason for the error because all you see is the message "error" from $stderr.puts "error". With popen3, the stderr from the command line vanishes!

I'm using ruby 3.0.1p64 on macOS 11.3.1 .

A complete example

~/tmp $ ./somebinary
dyld: Library not loaded: /usr/local/opt/gcc/lib/gcc/10/libgfortran.5.dylib
  Referenced from: /Users/furue/tmp/./somebinary
  Reason: image not found
fish: Job 1, './somebinary' terminated by signal SIGABRT (Abort)
~/tmp [134] $ ruby --version
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [arm64-darwin20]
~/tmp $ cat try-popen3.rb
require "open3"
begin
  Open3.popen3("./somebinary") {|i,o,e,t|
    $stderr.puts "in popen . . . "
    i.puts "some string"
  }
rescue
  $stderr.puts "error in rescue . . . "
  exit(1)
end
~/tmp $ ruby try-popen3.rb
in popen . . .
~/tmp $ cat try-popen3-standarderror.rb
require "open3"
begin
  Open3.popen3("./somebinary") {|i,o,e,t|
    $stderr.puts "in popen . . . "
    i.puts "some string"
  }
rescue StandardError => e
  $stderr.puts e.message
  $stderr.puts e.backtrace.inspect
  $stderr.puts "error in rescue . . . "
  exit(1)
end
~/tmp $ ruby try-popen3-standarderror.rb
in popen . . .
~/tmp $ cat try-popen.rb
require "open3"
begin
  IO.popen("./somebinary") {|i|
    $stderr.puts "in popen . . . "
    i.puts "some string"
  }
rescue
  $stderr.puts "error in rescue . . . "
  exit(1)
end
~/tmp $ ruby try-popen.rb
in popen . . .
dyld: Library not loaded: /usr/local/opt/gcc/lib/gcc/10/libgfortran.5.dylib
  Referenced from: /Users/furue/tmp/./somebinary
  Reason: image not found
error in rescue . . .
~/tmp [1] $ cat try-popen-standarderror.rb
require "open3"
begin
  IO.popen("./somebinary") {|i|
    $stderr.puts "in popen . . . "
    i.puts "some string"
  }
rescue StandardError => e
  $stderr.puts e.message
  $stderr.puts e.backtrace.inspect
  $stderr.puts "error in rescue . . . "
  exit(1)
end
~/tmp $ ruby try-popen-standarderror.rb
in popen . . .
dyld: Library not loaded: /usr/local/opt/gcc/lib/gcc/10/libgfortran.5.dylib
  Referenced from: /Users/furue/tmp/./somebinary
  Reason: image not found
not opened for writing
["try-popen-standarderror.rb:5:in `write'", "try-popen-standarderror.rb:5:in `puts'", "try-popen-standarderror.rb:5:in `block in <main>'", "try-popen-standarderror.rb:3:in `popen'", "try-popen-standarderror.rb:3:in `<main>'"]
error in rescue . . .
~/tmp [1] $
0

There are 0 answers