From: Robert Klemme Date: 2009-11-06T19:15:52+09:00 Subject: Re: reading from an external process with IO.popen 2009/11/5 Robert Citek : > Hello all, > > I'm trying to wrap my head around IO.popen with some simple examples > that send data to and read data from an > external process.  I've create a sample case in the shell like this: > > $ { echo hello ; sleep 2 ; echo world; } | cat > hello > world > > I've written the same in ruby like so, which works: > > $ cat foo.rb > #!/usr/bin/env ruby > if $0 == __FILE__ >  cat = IO.popen("cat", "w+") ; >  cat.puts("hello, ") ; >  puts(cat.gets) ; >  sleep 2 ; >  cat.puts("world") ; >  puts(cat.gets) ; > end > > $ ./foo.rb > hello > world > > However, if I change the cat command to a sed command, the ruby > version no longer works.  The command-line equivalent does work, but > the ruby version waits forever and has to be interrupted: That's probably because you do not close the write end of the pipe in Ruby code. Also, it's better to place the reading portion in a separate thread in order to prevent deadlocks. And, please use the block form of IO.popen which is more robust. Try this pattern: IO.popen("cat", "w+") do |cat| # background output t = Thread.new { cat.each {|l| puts l} } # main work cat.puts "hello, " sleep 2 cat.puts "world" # terminate processing: cat.close_write t.join end Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/