Best Practices With Stdin in Ruby

How can you check for STDIN input in a Ruby script?

This is something that's done in Linux a lot:

#!/usr/bin/env ruby

str = (STDIN.tty?) ? 'not reading from stdin' : $stdin.read
puts str

>> $ ruby test.rb
>> not reading from stdin
>> $ echo "reading from stdin" | ruby test.rb
>> reading from stdin

Detecting stdin content in Ruby

Look at $stdin.tty?

ruby cat.rb
# $stdin.tty? -> true

echo hello | ruby cat.rb
# $stdin.tty? -> false

How can I get piped data with arguments on Ruby2.4

It seems that in ruby you want to read from ARGF. It handles files passed as filenames or piped to your program.

What does #tty? on STDIN mean / do in ruby?

Seems like http://www.jstorimer.com/blogs/workingwithcode/7766125-writing-ruby-scripts-that-respect-pipelines supplies the most concise description of what #tty? does:

Ruby's IO#isatty method (aliased as IO#tty?) will tell you whether or not the IO in question is attached to a terminal. Calling it on $stdout, for instance, when it's being piped will return false.

Here is some relevant info that you may find useful:

  • Detecting stdin content in Ruby
  • How can you check for STDIN input in a Ruby script?
  • https://stackoverflow.com/a/273605
  • https://gist.github.com/timuruski/6072363

Background meaning via What do pty and tty mean?:

In UNIX, /dev/tty* is any device that acts like a "teletype", ie, terminal. (Called teletype because that's what we had for terminals in those benighted days.)

In the spirit of the question, here's an example of writing to /dev/tty from http://zetcode.com/lang/rubytutorial/io/:

#!/usr/bin/ruby

fd = IO.sysopen "/dev/tty", "w"
ios = IO.new(fd, "w")
ios.puts "ZetCode"
ios.close

Piping stdin to ruby script via `myapp | myscript.rb`

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.

Ruby STDIN, blocking vs not blocking

So the short answer is yes, you are getting an EOF from the pipe. Because the way echo works is that it's going to open the pipe for writing, write to it, then close (i.e. send EOF). Then a new call to echo will open it back up, read to it, and then close.

If you had instead used a program that printed lines of a file after a 3 second sleep, you would see that your application would perform blocking waits until that one exits (at which point the never-ending EOFs would return).

# slow_write.rb
ARGF.each do |line|
puts line
STDOUT.flush
sleep 3
end

I should note that this behavior is not specific to Ruby. The C stdlio library has the exact same behavior and since most languages use C primitives as their basis they have the same behavior as well.



Related Topics



Leave a reply



Submit