Popen in non-blocking mode

I want to execute a program which prompts for commads from standard
input and returns responses to standard output, this process repeats
several times. I want to execute it from a ruby application. I tried
to use a popen call to do it, but it do not flush the output until
input channel is closed. I need to know what the process request
before sending a response.

Regards


Saludos

Juan Carlos

“¡¡Viva lo rancio!!”

Urizev wrote:

I want to execute a program which prompts for commads from standard
input and returns responses to standard output, this process repeats
several times. I want to execute it from a ruby application. I tried
to use a popen call to do it, but it do not flush the output until
input channel is closed. I need to know what the process request
before sending a response.

It’s hard to tell what you mean by ‘output’ and ‘input’. There are two
sides to a pipe so side1’s output is side2’s input and side2’s output is
side1’s input. So, when you say it doesn’t flush the output, what do
you mean? What is it?

Also, what are you referring to when you say ‘process’? When you call
popen, you are starting what is typically called a “subprocess”. In
any case, there are two processes, so which one are you referring to?

If something is buffering output, then program it so that it doesn’t
buffer output, i.e. call flush. If you are unable to reprogram some
code somewhere to call flush, then I think the only way you can make it
flush is by causing one side to terminate, which automatically flushes
the pipe.

Urizev wrote:

I want to execute a program which prompts for commads from standard
input and returns responses to standard output, this process repeats
several times. I want to execute it from a ruby application. I tried
to use a popen call to do it, but it do not flush the output until
input channel is closed. I need to know what the process request
before sending a response.

Regards

this question was repeated over and over a least 20 times (quick google
search spawned 10 threads) and answer ultimatelly as the same - someone
already did it - use open4 gem / visit codeforpeople.com website

If something is buffering output, then program it so that it doesn’t
buffer output, i.e. call flush.

Based on my own experiences, I think the OP is in a situation where
he
is looking for some kind of peekchar functionality (with some
timeout)
to check if there is some output to consume. He would have to give us
a
code example but I suspect he tries to do something like:

inout = IO.popen('ruby', File::RDWR)
inout.read

Which is tricky to handle but feasible when consuming the output
charwise and if one can tell the interpreter is ready for input and
won’t output any new characters.

Anyway, the better solution would be to use open3, I think. There is
a
windows-implementation somewhere I think but I never tried it.

On Oct 6, 2007, at 5:17 AM, Urizev wrote:

I want to execute a program which prompts for commads from standard
input and returns responses to standard output, this process repeats
several times. I want to execute it from a ruby application. I tried
to use a popen call to do it, but it do not flush the output until
input channel is closed. I need to know what the process request
before sending a response.

the general concepts are:

IO.popen cmd, ‘r+’ do |pipe|

pipe.sync = true ### you can do this once

loop do
buf = pipe.gets

 case buf
   when /A/
     pipe.puts 'response_A'
   when /B/
     pipe.puts 'response_B'
 end

 pipe.flush ### or this after each write

end

end

kind regards.

a @ http://codeforpeople.com/

On Oct 6, 2007, at 9:10 AM, Marcin R. wrote:

this question was repeated over and over a least 20 times (quick
google search spawned 10 threads) and answer ultimatelly as the
same - someone already did it - use open4 gem / visit
codeforpeople.com website

heh - i wrote that i and i didn’t suggest that. good one though! :wink:

actually that will only help on *nix. dunno if that helps the OP or
not? otherwise check out both open4 and session - both on http://
codeforpeople.com/

session.rb shows how to communicate with a subprocess as you are -
check out the Bash and IDL clients.

cheers.

a @ http://codeforpeople.com/

ps. on windows you may want to check out systemu, also on
codeforpeople.

Thank you very much for the pointer.

On Oct 6, 2007, at 7:00 PM, Daniel DeLorme wrote:

end

and I get the output in one big block after 10 seconds. Does open3/
open4 change that? Somehow I doubt it.

not directly, although setting the STDOUT.sync=true before running
popen will have that affect on some systems - where that’s inherited
parent → child.

you are correct that you can’t completly control the buffering
behaviour of child processes, however.

cheers.

a @ http://codeforpeople.com/

On Oct 6, 2007, at 9:20 AM, tho_mica_l wrote:

Anyway, the better solution would be to use open3, I think. There is
a
windows-implementation somewhere I think but I never tried it.

search the archives - it has a fatally flawed impl.

regards.

ps. on windows you may want to check out systemu, also on
codeforpeople.

regards.

a @ http://codeforpeople.com/

ara.t.howard wrote:

the general concepts are:

IO.popen cmd, ‘r+’ do |pipe|
pipe.sync = true ### you can do this once

Except that doesn’t work. If the subprocess doesn’t flush its output,
setting sync to true won’t change anything. I tested with this:

IO.popen(“ruby -e ‘10.times{puts rand;sleep 1}’”) do |pipe|
pipe.sync = true
while str = pipe.gets
puts str
end
end

and I get the output in one big block after 10 seconds. Does open3/open4
change that? Somehow I doubt it.

Daniel

2007/10/7, Nobuyoshi N. [email protected]:

Use PTY.

What is PTY?


Nobu Nakada


Saludos

Juan Carlos

“¡¡Viva lo rancio!!”

Hi,

At Sat, 6 Oct 2007 20:17:40 +0900,
Urizev wrote in [ruby-talk:272872]:

I want to execute a program which prompts for commads from standard
input and returns responses to standard output, this process repeats
several times. I want to execute it from a ruby application. I tried
to use a popen call to do it, but it do not flush the output until
input channel is closed. I need to know what the process request
before sending a response.

Use PTY.

On Oct 8, 2007, at 6:00 AM, Urizev wrote:

before sending a response.

Use PTY.

What is PTY?

ruby included a library for manipulating them.

a @ http://codeforpeople.com/

this worked for me but is kind of lame

stdout = “”
stderr = “”
process = Open4.background(cmd, 0=>"", 1=>stdout, 2=>stderr)

puts process.pid

while process.status do

puts stdout unless stdout == “”
puts stderr unless stderr == “”

stdout.replace("")
stderr.replace("")

sleep 0.25
end

puts process.exitstatus

Daniel DeLorme wrote in post #567176:

ara.t.howard wrote:

the general concepts are:

IO.popen cmd, ‘r+’ do |pipe|
pipe.sync = true ### you can do this once

Except that doesn’t work. If the subprocess doesn’t flush its output,
setting sync to true won’t change anything. I tested with this:

IO.popen(“ruby -e ‘10.times{puts rand;sleep 1}’”) do |pipe|
pipe.sync = true
while str = pipe.gets
puts str
end
end

and I get the output in one big block after 10 seconds. Does open3/open4
change that? Somehow I doubt it.

Daniel

On Mon, Oct 17, 2011 at 10:44 PM, Jared Grippe
[email protected] wrote:

this worked for me but is kind of lame

Daniel’s point is that you can do what you want in the Ruby script: it
won’t work if you cannot convince the other process to flush its
output quicker (see initial posting of the thread).

Daniel DeLorme wrote in post #567176:

ara.t.howard wrote:

the general concepts are:

IO.popen cmd, ‘r+’ do |pipe|
pipe.sync = true ### you can do this once

Except that doesn’t work. If the subprocess doesn’t flush its output,
setting sync to true won’t change anything.

Cheers

robert