可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I want to deal with the command line input in Ruby:
> cat input.txt | myprog.rb
> myprog.rb < input.txt
> myprog.rb arg1 arg2 arg3 ...
What is the best way to do it? In particular I want to deal with blank STDIN, and I hope for an elegant solution.
#!/usr/bin/env ruby
STDIN.read.split("\n").each do |a|
puts a
end
ARGV.each do |b|
puts b
end
回答1:
Following are some things I found in my collection of obscure Ruby.
So, in Ruby, a simple no-bells implementation of the Unix command cat
would be:
#!/usr/bin/env ruby
puts ARGF.read
ARGF
is your friend when it comes to input; it is a virtual file that gets all input from named files or all from 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
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.
#++
Credit to:
- http://www.oreillynet.com/ruby/blog/2007/04/trivial_scripting_with_ruby.html#comment-565558
- http://blog.nicksieger.com/articles/2007/10/06/obscure-and-ugly-perlisms-in-ruby
回答2:
Ruby provides another way to handle STDIN: The -n flag. It treats your entire program as being inside a loop over STDIN, (including files passed as command line args). See e.g. the following 1-line script:
#!/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
回答3:
I am not quite sure what you need, but I would use something like this:
#!/usr/bin/env ruby
until ARGV.empty? do
puts "From arguments: #{ARGV.shift}"
end
while a = gets
puts "From stdin: #{a}"
end
Note that because ARGV array is empty before first gets
, Ruby won't try to interpret argument as text file from which to read (behaviour inherited from Perl).
If stdin is empty or there is no arguments, nothing is printed.
Few test cases:
$ 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!
回答4:
Something like this perhaps?
#/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
Example:
> 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
回答5:
while STDIN.gets
puts $_
end
while ARGF.gets
puts $_
end
This is inspired by Perl:
while(<STDIN>){
print "$_\n"
}
回答6:
I'll add that in order to use ARGF
with parameters, you need to clear ARGV
before calling ARGF.each
. This is because ARGF
will treat anything in ARGV
as a filename and read lines from there first.
Here's an example 'tee' implementation:
File.open(ARGV[0], 'w') do |file|
ARGV.clear
ARGF.each do |line|
puts line
file.write(line)
end
end
回答7:
I do something like this :
all_lines = ""
ARGV.each do |line|
all_lines << line + "\n"
end
puts all_lines
回答8:
It seems most answers are assuming the arguments are filenames containing content to be cat'd to the stdin. Below everything is treated as just arguments. If STDIN is from the TTY, then it is ignored.
$ cat tstarg.rb
while a=(ARGV.shift or (!STDIN.tty? and STDIN.gets) )
puts a
end
Either arguments or stdin can be empty or have data.
$ cat numbers
1
2
3
4
5
$ ./tstarg.rb a b c < numbers
a
b
c
1
2
3
4
5
回答9:
Quick and simple:
STDIN.gets.chomp == 'YES'