在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'