3

I have an app that runs continuously, dumping output from a server and sending strings to stdout. I want to process this output with a Ruby script. The strings are \n-terminated.

For example, I'm trying to run this on the command line:

myapp.exe | my_script.rb

...with my_script.rb defined as:

while $stdin.gets
    puts $_
end

I ultimately am going to process the strings using regexes and display some summary data, but for now I'm just trying to get the basic functionality hooked up. When I run the above, I get the following error:

my_script.rb:1:in `gets': Bad file descriptor (Errno::EBADF)
        from my_script.rb:1

I am running this on Windows Server 2003 R2 SP2 and Ruby 1.8.6.

How do I continuously process stdin in a Ruby script? (Continuously as in not processing a file, but running until I kill it.)

EDIT:

I was able to make this work, sort of. There were several problems standing in my way. For one thing, it may be that using Ruby to process the piped-in stdin from another process doesn't work on Windows 2003R2. Another direction, suggested by Adrian below, was to run my script as the parent process and use popen to connect to myapp.exe as a forked child process. Unfortunately, fork isn't implemented in Windows, so this didn't work either.

Finally I was able to download POpen4, a RubyGem that does implement popen on Windows. Using this in combination with Adrian's suggestion, I was able to write this script which does what I really want -- processes the output from myapp.exe:

file: my_script.rb

require 'rubygems'
require 'popen4'

 status =
    POpen4::popen4("myapp.exe") do |stdout, stderr, stdin, pid|
        puts pid
        while s = stdout.gets
            puts s
        end

    end

This script echoes the output from myapp.exe, which is exactly what I want.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • 1
    Have you tried running the ruby script without the pipe and typing things in to test it? Your code works on my computer. – Adrian Jul 07 '10 at 18:09
  • @Adrian: Yes, my script runs fine by itself. It echoes everything I type in, as expected and desired. – John Dibling Jul 07 '10 at 18:20
  • Try just plain `gets`, without the `$stdin`. If that doesn't work, you might have to examine the output of `myapp.exe` for non-printable characters with another ruby script, using `IO.popen`. – Adrian Jul 07 '10 at 18:32
  • @Adrian: Unfortunately `fork` doesn't work on Windows, and `popen` uses `fork`. Is there some secret incantation I can employ to get it to work? – John Dibling Jul 07 '10 at 19:05
  • The only thing I can think of would be to temporarily rewrite `myapp.exe` to exit after a certain number of lines and then use `%x`. – Adrian Jul 07 '10 at 19:15
  • @Adrian: I got it to work. Your comment didn't quite get me there, but it set me on the path. I'll edit my post with the solution I used. If you change your comment about `popen` as an answer, I'll accept it. – John Dibling Jul 07 '10 at 19:24

3 Answers3

2

Try just plain gets, without the $stdin. If that doesn't work, you might have to examine the output of myapp.exe for non-printable characters with another ruby script, using IO.popen.

Adrian
  • 14,931
  • 9
  • 45
  • 70
0

gets doesn't always use stdin but instead tries to open a file.

See SO.

Community
  • 1
  • 1
mcandre
  • 22,868
  • 20
  • 88
  • 147
0

Try executing your Ruby script by explicitly calling ruby:

myapp.exe | ruby my_script.rb

I've experienced some odd behavior using stdin in Ruby when relying on Windows to invoke the correct program based on the file associations.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
jason.rickman
  • 13,931
  • 1
  • 22
  • 14