我想在Ruby中处理命令行输入:

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

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

#!/usr/bin/env ruby

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

ARGV.each do |b|
    puts b
end

当前回答

我要补充一点,为了带参数使用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

其他回答

也许是这样的?

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

似乎大多数答案都假设参数是包含要添加到stdin的内容的文件名。以下的一切都被视为只是论点。如果STDIN来自TTY,那么它将被忽略。

$ cat tstarg.rb

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

参数或stdin都可以为空或有数据。

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

Ruby提供了另一种处理STDIN的方法:-n标志。它将整个程序视为在STDIN上的循环中(包括作为命令行参数传递的文件)。参见以下一行脚本:

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

你也可以使用STDIN。each_line和STDIN.each_line。To_a将其作为数组获取。

e.g.

STDIN.each_line do |line|
  puts line
end
while STDIN.gets
  puts $_
end

while ARGF.gets
  puts $_
end

这是受到Perl的启发:

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