在Ruby中使用 STDIN 的最佳实践?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (9)
  • 关注 (0)
  • 查看 (222)

我想处理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
提问于
用户回答回答于
用户回答回答于

似乎大多数答案都是假设参数是文件名,其中包含要通过 cat 发送到 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
用户回答回答于

我是这样做的:

all_lines = ""
ARGV.each do |line|
  all_lines << line + "\n"
end
puts all_lines
用户回答回答于

我会加入这个来使用 ARGF,你需要在调用 ARGF.each 前清除ARGV。这是因为 ARGF 将读入的第一个内容作为文件名。

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

File.open(ARGV[0], 'w') do |file|
  ARGV.clear

  ARGF.each do |line|
    puts line
    file.write(line)
  end
end
用户回答回答于
while STDIN.gets
  puts $_
end

while ARGF.gets
  puts $_
end

这是来自 Perl 激发的灵感

while(<STDIN>){
  print "$_\n"
}
用户回答回答于

大概是这样的

#/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
用户回答回答于

我不太清楚你想要什么,但我会用这样的方法来处理:

#!/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不会尝试将参数解释为要读取的文本文件(从Perl继承的行为)。

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

一些测试用例

$ 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!
用户回答回答于

Ruby 提供了另外一种处理 STDIN 的方法,使用 -n 标志。它将整个程序视为 STDIN 上的 Loop,文件名也会传入。具体参考下面的脚本。

#!/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
用户回答回答于

下面是我在我Ruby集合中发现的一些东西。

在Ruby中,unix命令的一个简单的无提醒的实现。

cat代码如下:

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

ARGF是来自输入的参数;它是一个虚拟文件,它可以从命名文件或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

虽然,我们没有得到Ruby中的钻石操作符,但是我们得到了ARGF作为替补。

虽然很难理解,但实际上是很有用的。

考虑一下这个程序,它将版权标题放在适当的位置到命令行中提到的每个文件的适当位置:

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

扫码关注云+社区

领取腾讯云代金券