How to Check for Stdin Input in a Ruby Script

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

Receiving input from STDIN in Ruby

Ruby may hold output in a buffer before writing to STDOUT, and write once an indeterminate amount of data has been printed. If you change your code to this:

#!/usr/bin/env ruby

while line = gets.chomp do
puts line
STDOUT.flush
# $stdout.flush works too, though the difference
# is outside the scope of this question
end

You can expect to see the output before you close the input stream.

As for "^C the client before the server", closing the process immediately will disregard all of the data which has not yet been flushed.

Testing STDIN in Ruby

You can simply stub STDIN:

it "takes user's name and returns it" do
output = capture_standard_output { game.ask_for_name }
expect(output).to eq "What shall I call you today?"
allow(STDIN).to receive(:gets) { 'joe' }
expect(game.ask_for_name).to eq 'Joe'
end

Actually, you can do the same with STDOUT, without needing to change $stdout:

it "takes user's name and returns it" do
expect(STDOUT).to receive(:puts).with("What shall I call you today?")
allow(STDIN).to receive(:gets) { 'joe' }
expect(game.ask_for_name).to eq 'Joe'
end

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

How to detect if a Ruby script is running through a shell pipe?

Use $stdout.isatty or more idiomatically, $stdout.tty?. I created a little test.rb file to demonstrate, contents:

puts $stdout.isatty

Results:

$ ruby test.rb
true

$ ruby test.rb | cat
false

Reference: https://ruby-doc.org/core/IO.html#method-i-isatty

How do I listen to STDIN input without pausing my script?

Not sure where are the commands you want to "continue running" in your example. Try this small script:

Thread.new do
loop do
s = gets.chomp
puts "You entered #{s}"
exit if s == 'end'
end
end

i = 0
loop do
puts "And the script is still running (#{i})..."
i += 1
sleep 1
end

Reading from STDIN is done in a separate thread, while the main script continues to work.



Related Topics



Leave a reply



Submit