about

writing

contact

Multiple Input Locations From Bash Into Ruby

By eric

2010-05-13

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.

12345

@opts = OptionParser.newdo|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.

12345678910111213

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}"}rescueErrno::EAGAIN
threads.delete(0)# Remove this thread since we won't be reading from $stdinend}.run

Now its time for the files.

12345678

@files.eachdo|file|
threads.pushThread.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: