在Ruby中使用STDIN的最佳做法?

我想处理Ruby中的命令行input:

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

什么是最好的办法呢? 特别是我想处理空白的STDIN,我希望能有一个优雅的解决scheme。

 #!/usr/bin/env ruby STDIN.read.split("\n").each do |a| puts a end ARGV.each do |b| puts b end 

以下是我在我的collections晦涩ruby中发现的一些事情。

因此,在Ruby中,Unix命令cat一个简单的无声的实现将是:

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

当涉及到input时, ARGF是你的朋友; 它是一个虚拟文件,从命名文件或全部来自STDIN的所有input。

 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 

谢天谢地,我们没有得到Ruby的钻石操作员,但是我们确实取得了ARGF的代替权。 虽然不起眼,但事实certificate,这是有用的。 考虑这个程序,这个程序在命令行中提到的每一个文件都预置了版权头文件(感谢另一个Perlism, -i ):

 #!/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. #++ 

归功于:

Ruby提供了另一种处理STDIN的方法:-n标志。 它将整个程序视为在STDIN循环内(包括作为命令行parameter passing的文件)。 见例如下面的1行脚本:

 #!/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 

我不太清楚你需要什么,但我会用这样的东西:

 #!/usr/bin/env ruby until ARGV.empty? do puts "From arguments: #{ARGV.shift}" end while a = gets puts "From stdin: #{a}" end 

请注意,由于ARGV数组在第一次gets之前是空的,因此Ruby不会尝试将参数解释为从中读取的文本文件(从Perlinheritance的行为)。

如果stdin是空的或没有参数,则不会打印任何内容。

几个testing用例:

 $ cat input.txt | ./myprog.rb From stdin: line 1 From stdin: line 2 $ ./myprog.rb arg1 arg2 arg3 From arguments: arg1 From arguments: arg2 From arguments: arg3 hi! From stdin: hi! 

也许这样的事情?

 #/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 

例:

 > 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 
 while STDIN.gets puts $_ end while ARGF.gets puts $_ end 

这受Perl的启发:

 while(<STDIN>){ print "$_\n" } 

我将补充说明,为了使用参数使用ARGF ,您需要在调用ARGF.each之前清除ARGV 。 这是因为ARGF会将ARGV中的任何内容视为文件名,并首先从那里读取行。

以下是一个示例“tee”的实现:

 File.open(ARGV[0], 'w') do |file| ARGV.clear ARGF.each do |line| puts line file.write(line) end end 

我做这样的事情:

 all_lines = "" ARGV.each do |line| all_lines << line + "\n" end puts all_lines 

看来大多数答案都假定参数是包含要被标记到stdin的内容的文件名。 在一切之下被视为只是论点。 如果STDIN来自TTY,则忽略。

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

参数或标准input可以是空的或有数据。

 $ cat numbers 1 2 3 4 5 $ ./tstarg.rb abc < numbers a b c 1 2 3 4 5 

快速简单:

STDIN.gets.chomp == 'YES'