Best practices with STDIN in Ruby?

2019-01-03 07:18发布

I want to deal with the command line input in Ruby:

> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...

What is the best way to do it? In particular I want to deal with blank STDIN, and I hope for an elegant solution.

#!/usr/bin/env ruby

STDIN.read.split("\n").each do |a|
   puts a
end

ARGV.each do |b|
    puts b
end

标签: ruby stdin
9条回答
地球回转人心会变
2楼-- · 2019-01-03 07:49

It seems most answers are assuming the arguments are filenames containing content to be cat'd to the stdin. Below everything is treated as just arguments. If STDIN is from the TTY, then it is ignored.

$ cat tstarg.rb

while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
  puts a
end

Either arguments or stdin can be empty or have data.

$ cat numbers 
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
查看更多
Deceive 欺骗
3楼-- · 2019-01-03 07:50

I do something like this :

all_lines = ""
ARGV.each do |line|
  all_lines << line + "\n"
end
puts all_lines
查看更多
叼着烟拽天下
4楼-- · 2019-01-03 07:57

Following are some things I found in my collection of obscure Ruby.

So, in Ruby, a simple no-bells implementation of the Unix command cat would be:

#!/usr/bin/env ruby
puts ARGF.read

ARGF is your friend when it comes to input; it is a virtual file that gets all input from named files or all from STDIN.

ARGF.each_with_index do |line, idx|
    print ARGF.filename, ":", idx, ";", line
end

# print all the lines in every file passed via command line that contains login
ARGF.each do |line|
    puts line if line =~ /login/
end

Thank goodness we didn’t get the diamond operator in Ruby, but we did get ARGF as a replacement. Though obscure, it actually turns out to be useful. Consider this program, which prepends copyright headers in-place (thanks to another Perlism, -i) to every file mentioned on the command-line:

#!/usr/bin/env ruby -i

Header = DATA.read

ARGF.each_line do |e|
  puts Header if ARGF.pos - e.length == 0
  puts e
end

__END__
#--
# Copyright (C) 2007 Fancypants, Inc.
#++

Credit to:

查看更多
\"骚年 ilove
5楼-- · 2019-01-03 07:57

Something like this perhaps?

#/usr/bin/env ruby

if $stdin.tty?
  ARGV.each do |file|
    puts "do something with this file: #{file}"
  end
else
  $stdin.each_line do |line|
    puts "do something with this line: #{line}"
  end
end

Example:

> cat input.txt | ./myprog.rb
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb < input.txt 
do something with this line: this
do something with this line: is
do something with this line: a
do something with this line: test
> ./myprog.rb arg1 arg2 arg3
do something with this file: arg1
do something with this file: arg2
do something with this file: arg3
查看更多
We Are One
6楼-- · 2019-01-03 07:57

Quick and simple:

STDIN.gets.chomp == 'YES'

查看更多
ら.Afraid
7楼-- · 2019-01-03 08:02

Ruby provides another way to handle STDIN: The -n flag. It treats your entire program as being inside a loop over STDIN, (including files passed as command line args). See e.g. the following 1-line script:

#!/usr/bin/env ruby -n

#example.rb

puts "hello: #{$_}" #prepend 'hello:' to each line from STDIN

#these will all work:
# ./example.rb < input.txt
# cat input.txt | ./example.rb
# ./example.rb input.txt
查看更多
登录 后发表回答