I would like to know if there is a portable way to check the Ruby script, whether it will block if it tries to read from STDIN. The following is an approach that works for Unix (and Cygwin), but not for native Win32. (It is based on the Perl approach that I learned a long time ago.)
$ cat read-stdin.rb
#! /usr/bin/ruby # test of reading from STDIN require 'fcntl' # Trace info on input objects $stdout.sync=TRUE if $DEBUG # make sure standard output and error synchronized $stderr.print "ARGV=#{ARGV}\n" if $DEBUG $stderr.print "ARGF=#{ARGF}\n" if $DEBUG # See if input available, showing usage statement if not blocking_stdin = FALSE if (defined? Fcntl::F_GETFL) then $stderr.print "F_GETFL=#{Fcntl::F_GETFL} O_RDWR=#{Fcntl::O_RDWR}\n" if $DEBUG flags = STDIN.fcntl(Fcntl::F_GETFL, 0) $stderr.print "flags=#{flags}\n" if $DEBUG blocking_stdin = TRUE if ((flags & Fcntl::O_RDWR) == Fcntl::O_RDWR) $stderr.print "blocking_stdin=#{blocking_stdin}\n" if $DEBUG end if (blocking_stdin && (ARGV.length == 0)) then $stderr.print "usage: #{$0} [-]\n" Process.exit end # Read input and output it $stderr.print "Input:\n" if $DEBUG input_text = ARGF.read() $stderr.print "Output:\n" if $DEBUG print "#{input_text}\n"
Here is an interaction without debugging:
$ grep -v DEBUG read-stdin.rb >| /tmp/simple-read-stdin.rb $ echo hey | ruby /tmp/simple-read-stdin.rb hey $ ruby /tmp/simple-read-stdin.rb usage: /tmp/simple-read-stdin.rb [-]
Here is the debugging interaction:
$ echo hey | ruby -d read-stdin.rb ARGV= ARGF=ARGF F_GETFL=3 O_RDWR=2 flags=65536 blocking_stdin=false Input: Output: hey $ ruby -d read-stdin.rb ARGV= ARGF=ARGF F_GETFL=3 O_RDWR=2 flags=98306 blocking_stdin=true usage: read-stdin.rb [-]
source share