Multiple Input Locations From Bash Into Ruby

I have been trying to figure out how, while using OptionParser to be able to check for files being input on the command line and if they don’t exist, check other input streams (like Bash). This initially wasn’t very easy since input streams are blocking. So with a little help from friends (thanks roberto), I was able to use his method of non-blocking IO and wrap it in a begin/rescue block. I also took a little advice given in this Stack Overflow question called Best Practices with STDIN in Ruby.

First we need to get the file list off the command line and assume that anything left are files.

@opts = OptionParser.new do |o|
...
end
@opts.parse!(args)
@files = args

Since we are using threads, I open up a thread for STDIN and killed it when we run out of input.

require 'fcntl'
threads = Array.new

# Set $stdin to be non-blocking
$stdin.fcntl(Fcntl::F_SETFL,Fcntl::O_NONBLOCK)                                        

threads[0] = Thread.new {
  begin
    $stdin.each_line { |line|  puts "STDIN: #{line}" }
  rescue Errno::EAGAIN
    threads.delete(0) # Remove this thread since we won't be reading from $stdin
  end
}.run

Now its time for the files.

@files.each do |file|
  threads.push Thread.new {
    # do stuff with 'file'
  }
end

# Put it all together and have the threads run
threads.each { |thread|  thread.join }

Using these code snippets, you will be able to use input from both files on the command line and STDIN:

  1. $ myscript.rb file1 file2
  2. $ cat foo | myscript.rb file1 file2
  3. $ myscript.rb file1 file2 < foo

Related posts:

  1. Should I Mock Kernel#exit
  2. Parsing Ini Files With Ruby
  3. Git Branch Name in Your Bash Prompt
Posted in Ruby. Tags: , . 4 Comments »
  • http://topsy.com/trackback?utm_source=pingback&utm_campaign=L1&url=http://eric.lubow.org/2010/ruby/multiple-input-locations-from-bash-into-ruby/ Tweets that mention Multiple Input Locations From Bash Into Ruby | Erics Tech Blog — Topsy.com

    [...] This post was mentioned on Twitter by Eric Lubow. Eric Lubow said: Non-Blocking I/O From a Bash Pipe with #Ruby: http://bit.ly/bBEXNW [...]

  • http://twitter.com/ilpuccio Raoul Bonnal

    Hello,
    does it work with files only?

  • http://eric.lubow.org Eric Lubow

    Example 3 above shows that it can work with a file but you can easily substitute text like this:nn$ myscript.rb file1 file2 < “This is my 3rd method of input”

  • http://twitter.com/ilpuccio Raoul Bonnal

    Hello Eric,
    please take a look to this code, what is wrong with it ?
    http://github.com/helios/Ruby-Generic-Input-STDIN-Files/blob/master/i-std-ff.rb
    nnI’d like to create a generic library, what do yuo think about it?