Ah. You're right, of course.  I could have sworn that I tried using 
pipe.close_write before and the problem remained, but apparently I was 
mistaken.

Notes:
   - "cat" was just to prove a point - the real issue was with 
"sendmail", but it seems to have the same solution.  My brief overview 
made me think session was not suited for sendmail, but perhaps I was 
wrong about that too?   I'll check it out.
   - the use of timeout was just to allow the test to exit when the hang 
occurred.  I didn't realize it fails on w32.  Is it Timeout that fails, 
or just when timeout is combined with IO reads?

Thanks again!
-Payton

ara.t.howard / noaa.gov wrote:
> On Tue, 31 Jan 2006, Payton Swick wrote:
> 
>> How does one check a pipe (created using IO.popen) to see if there is 
>> input waiting without using IO#eof or reading from the pipe?  Doing 
>> either of these seems to hang forever if the pipe is empty.
> 
> 
>     harp:~ > cat a.rb
>     IO.popen("cat", "r+") do |pipe|
>       pipe.puts 42
>       pipe.close_write
>       puts pipe.read
>     end
> 
> 
>     harp:~ > ruby a.rb
>     42
> 
> 
> 
> consider that cat reads stdin until eof is found.
> 
>> Here's an example:
>>
>> require 'timeout'
>> IO.popen("cat", "r+") do |pipe|
>> #   pipe.puts "hello world" # Uncomment this to prevent hang below.
> 
> 
> not really - only the first one.  continue to read an you'll still 
> hang.   this
> is because cat is still waiting on more stdin or eof.  so you must send 
> more or
> close the write end of the pipe to send eof.
> 
>>  Timeout::timeout(2) do
> 
> 
> never mix timeout with reads.  it fails on windoze - if you care.
> 
>>    if not pipe.eof? # This will hang if the pipe is empty.
> 
> 
> because cat is waiting for stdin and is not finsihed - cat will only 
> close it's
> stdout when it's done and it's only done when it's stdin has all been read.
> man 1 cat.
> 
>>      p pipe.getc
>>    end
>>  end
>> end
> 
> 
> 
> if you are on *nix you'll find my session module much easier to use:
> 
>     harp:~ > gem install session
>     Attempting local installation of 'session'
>     Local gem file not found: session*.gem
>     Attempting remote installation of 'session'
>     Updating Gem source index for: http://gems.rubyforge.org
>     Successfully installed session-2.4.0
>     harp:~ > cat a.rb
>     require "rubygems"
>     require "session"
>     require "stringio"
> 
> 
>     sh = Session::new
> 
>     stdin = "42"
>     stdout = StringIO::new
>     stderr = StringIO::new
> 
>     sh.execute "cat", "stdin" => stdin, "stdout" => stdout, "stderr" => 
> stderr
> 
>     puts stdout
> 
> 
>     harp:~ > ruby a.rb
>     42
> 
> 
> session can also be made to be thread-safe (eg use with timeout) if 
> needed.  see docs for more.
> 
> 
> kind regards.
> 
> 
> 
> -a