> 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
以下是我在我的冷门 Ruby 收藏中发现的一些东西。
So, in Ruby, a simple no-bells implementation of the Unix command
cat
would be:
#!/usr/bin/env ruby puts ARGF.read
ARGF
是处理输入的好帮手;它是一个虚拟文件,可以从指定文件或标准输入中获取所有输入。
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. #++
— http://blog.nicksieger.com/articles/2007/10/06/obscure-and-ugly-perlisms-in-ruby
来源:
idx
将是虚拟文件中连接所有输入的“行号”,而不是每个单独文件的行号。 - Alec Jacobson#!/usr/bin/env ruby -i
行在 Linux 上不起作用:https://dev59.com/M2855IYBdhLWcg3wg0nC - bfontaineRuby提供了另一种处理标准输入的方法:-n标志。它将您的整个程序视为在STDIN上循环(包括作为命令行参数传递的文件)。例如,请参见以下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 -n
无法工作,因为 "ruby -n" 会作为唯一的参数传递给 /usr/bin/env。更多细节请参见 此答案。如果显式地使用 ruby -n script.rb
运行脚本,则脚本将会被执行。 - artm我不太确定你需要什么,但我会使用类似于这样的东西:
#!/usr/bin/env ruby
until ARGV.empty? do
puts "From arguments: #{ARGV.shift}"
end
while a = gets
puts "From stdin: #{a}"
end
请注意,由于在第一次gets
之前ARGV数组为空,因此Ruby不会尝试将参数解释为要读取的文本文件(这是从Perl继承的行为)。
如果标准输入为空或没有参数,则不会输出任何内容。
少数测试案例:
$ 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"
}
简单易懂:
STDIN.gets.chomp == 'YES'
STDIN.each_line
和 STDIN.each_line.to_a
将其作为数组获取。STDIN.each_line do |line|
puts line
end
ARGF
,你需要在调用ARGF.each
之前清空ARGV
。这是因为ARGF
会将ARGV
中的任何内容视为文件名,并首先从那里读取行。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
看起来大多数答案都假定参数是包含要cat到stdin的内容的文件名。在下面的例子中,所有东西都被视为参数。如果STDIN来自TTY,则会被忽略。
$ cat tstarg.rb
while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
puts a
end
参数或标准输入可以为空或包含数据。
$ cat numbers
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
myprog.rb
的角度来看完全相同:input.txt
文件被附加到 stdin 上,shell 会为您管理。 - Mei