Playing with popen again

Why doesn't this work?

prog1 calls prog2... the latter starts by writing a line, then reading
a line. The former reads first, then writes.

It hangs indefinitely. When I kill prog1, it appears that I interrupted
a gets on each side.

What am I doing that's stupid?

Thanks,
Hal

# prog1
io = IO.popen("ruby prog2.rb","r+")
str = io.gets
puts "got: #{str}"
io.puts "junk"

str = io.gets
puts "got: #{str}"
io.puts "junk"

str = io.gets
puts "got: #{str}"
io.puts "junk"

#!/usr/local/bin/ruby
# prog2
puts "This is prompt 1"
gets
puts "This is 2nd prompt"
gets
puts "3rd/final prompt"
gets

$ ruby prog1.rb # and then ctl-C
prog1.rb:2:in `gets': Interrupt from prog1.rb:2
prog2.rb:3:in `gets': Interrupt from prog2.rb:3

This would be a side-effect of buffering. prog2.rb won't be sending
anything over the pipe until it's flushed (standard out is normally
line-buffered when connected to a terminal, but fully buffered when it's
not). If you add $stdout.flush after each puts in your prog2.rb then it
should work as expected.

You can check the status of whether autoflushing is on with IO#sync.
io.sync in prog1.rb should be true, $stdout.sync in prog2.rb should be
false (which means instead of flushing manually, you could do:
$stdout.sync = true in prog2.rb.)

I'm not extremely well-versed in Ruby so please accept my apologies if
this information is more Unix-centric than Ruby-centric.

Chris

···

On Fri, 04 Jun 2004 04:43 GMT, Hal Fulton <hal9000@hypermetrics.com> wrote:

It hangs indefinitely. When I kill prog1, it appears that I interrupted
a gets on each side.

# prog1
io = IO.popen("ruby prog2.rb","r+")
str = io.gets
puts "got: #{str}"
io.puts "junk"

str = io.gets
puts "got: #{str}"
io.puts "junk"

str = io.gets
puts "got: #{str}"
io.puts "junk"

#!/usr/local/bin/ruby
# prog2
puts "This is prompt 1"
gets
puts "This is 2nd prompt"
gets
puts "3rd/final prompt"
gets

stdout is only line buffered when it's a tty. in the case of an external
process it is completely buffered - you are seeing the operating system chose
not to send the output of prog2 because the buffer has not yet been filled.

   ~ > cat prog1
   io = IO.popen("ruby prog2","r+")
   3.times do |i|
     print "read #{ i } => "
     str = io.gets
     puts "<#{ str.inspect }>"
     io.puts
   end

   ~ > cat prog2

···

On Fri, 4 Jun 2004, Hal Fulton wrote:

Why doesn't this work?

prog1 calls prog2... the latter starts by writing a line, then reading
a line. The former reads first, then writes.

It hangs indefinitely. When I kill prog1, it appears that I interrupted
a gets on each side.

What am I doing that's stupid?

Thanks,
Hal

# prog1
io = IO.popen("ruby prog2.rb","r+")
str = io.gets
puts "got: #{str}"
io.puts "junk"

str = io.gets
puts "got: #{str}"
io.puts "junk"

str = io.gets
puts "got: #{str}"
io.puts "junk"

#!/usr/local/bin/ruby
# prog2
puts "This is prompt 1"
gets
puts "This is 2nd prompt"
gets
puts "3rd/final prompt"
gets

$ ruby prog1.rb # and then ctl-C
prog1.rb:2:in `gets': Interrupt from prog1.rb:2
prog2.rb:3:in `gets': Interrupt from prog2.rb:3

   #
   # magic bullet
   #
   STDOUT.sync = true

   3.times do |i|
     puts "prompt #{ i }"
     gets
   end

   ~ > ruby prog1
   read 0 => <"prompt 0\n">
   read 1 => <"prompt 1\n">
   read 2 => <"prompt 2\n">

cheers.

-a
--

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
A flower falls, even though we love it; and a weed grows, even though we do
not love it. --Dogen

===============================================================================