Checking for STDIN in ruby
A colleague was asking today how he could see if there’s data waiting on STDIN
in ruby (on Linux). On OS X, this is pretty straightforward:
if $stdin.stat.size > 0
puts "got something: #{STDIN.read}"
else
puts "nada"
end
That doesn’t work in Linux, though. After some digging, I found this post, which lead to:
require 'fcntl'
flags = STDIN.fcntl(Fcntl::F_GETFL, 0)
flags |= Fcntl::O_NONBLOCK
STDIN.fcntl(Fcntl::F_SETFL, flags)
begin
puts "got something: #{STDIN.read}"
rescue Errno::EAGAIN
puts "nada"
end
Which works on both platforms, but is (a) ugly (catching an exception), and (b) requires you to actually try to read from STDIN
.
In playing around with that, though, I noticed that STDIN.fcntl(Fcntl::F_GETFL, 0)
returned 0
if there was something on STDIN
, and something non-zero (2
in OSX and 32770
in Linux) if STDIN
was empty. So now the code is simple again:
require 'fcntl'
if STDIN.fcntl(Fcntl::F_GETFL, 0) == 0
puts "got something: #{STDIN.read}"
else
puts "nada"
end
I’m not sure how reliable that is on other platforms (it won’t work on Windows—fcntl is a Unix-y thing). If I’m understanding fcntl.h correctly, a return value of 2/32770 (0x8002) seems to indicate that the io stream in question is open for writing. I’m not sure if that is intended or just a side-effect. Anyone know?