Behavior of 'Open3.popen3' is different when use ruby 1.8.6 and 1.9.3, any solution?

#!/usr/bin/env ruby

require ‘open3’

x = ‘abc’
stdin, stdout, stderr = Open3.popen3("#{x}")
puts “go on running …”

‘abc’ is an unix command that doesn’t exist.

Use ruby 1.8.6
The error run popen3 stored in stderr, and the error don’t show on
screen, then script will go on to output “go on running …”

Use buby 1.9.3
The error run popen3 will show on screen, and the script exit directly

I want popen3 work as the manner when use 1.8.6, ie.(don’t show errors
on screen but just store it in stderr, and script can go on running
instead of exiting), is there any method can do this in 1.9.3?

2013/10/23 Previn L. [email protected]:

I want popen3 work as the manner when use 1.8.6, ie.(don’t show errors
on screen but just store it in stderr, and script can go on running
instead of exiting), is there any method can do this in 1.9.3?

Add “;” at the end of the command.

stdin, stdout, stderr = Open3.popen3(“#{x};”)

This forces Open3.popen3 to use a shell.

On Oct 23, 2013, at 2:18 AM, Previn L. [email protected] wrote:

Use ruby 1.8.6
The error run popen3 stored in stderr, and the error don’t show on
screen, then script will go on to output “go on running …”

Use buby 1.9.3
The error run popen3 will show on screen, and the script exit directly

I want popen3 work as the manner when use 1.8.6, ie.(don’t show errors
on screen but just store it in stderr, and script can go on running
instead of exiting), is there any method can do this in 1.9.3?

Wrap it in a begin/rescue block, and process the error properly. Since
1.9, spawn (which is what underlies Open3.popen3 (and others) will
execute a command directly, i.e. without calling the shell, if the
command is a single word and contains no spaces or shell characters, or,
if the arguments are single words, or an array of single words.

begin
si, so, se, wt = Open3.popen3(cmd)
rescue Exception => e

process exception here — if the command is not found, you should

have an Errno::ENOENT error
ensure

end

In the above, these will have the following results:

cmd = “ls” → runs directly from spawn
cmd = “ls -l” → runs under shell because of space (a shell char)
cmd = [“ls”, “-l”] → runs directly from spawn
cmd = “asdfasdf” (not a program) → spawn raises ENOENT, caught in rescue
cmd = “asdfasdf;” (not a program, but with shell character) → runs under
shell, shell returns stderr, no exception raised

For my dough, running under the shell adds extra cost, so I just run
directly with spawn, and deal with the exceptions in my script.

Tanaka A. wrote in post #1125314:

2013/10/23 Previn L. [email protected]:

I want popen3 work as the manner when use 1.8.6, ie.(don’t show errors
on screen but just store it in stderr, and script can go on running
instead of exiting), is there any method can do this in 1.9.3?

Add “;” at the end of the command.

stdin, stdout, stderr = Open3.popen3(“#{x};”)

This forces Open3.popen3 to use a shell.

Wow, it works, thank you so much!

tamouse m. wrote in post #1125396:

begin
si, so, se, wt = Open3.popen3(cmd)
rescue Exception => e

process exception here — if the command is not found, you should

have an Errno::ENOENT error
ensure

end

In the above, these will have the following results:

cmd = “ls” → runs directly from spawn
cmd = “ls -l” → runs under shell because of space (a shell char)
cmd = [“ls”, “-l”] → runs directly from spawn
cmd = “asdfasdf” (not a program) → spawn raises ENOENT, caught in rescue
cmd = “asdfasdf;” (not a program, but with shell character) → runs under
shell, shell returns stderr, no exception raised

For my dough, running under the shell adds extra cost, so I just run
directly with spawn, and deal with the exceptions in my script.

Hi tamouse_m,

Thank you so much for your guide with so detailed explanation, I’m more
clear with it now, many thanks.

Previn