Лучшие практики с STDIN в Ruby?
Я хочу иметь дело с вводом командной строки в 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
Ответы
Ответ 1
Ниже приведены некоторые вещи, которые я нашел в своей коллекции малоизвестного 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
в качестве замены. Хотя неясно, на самом деле это оказывается полезным. Рассмотрим эту программу, которая добавляет заголовки авторских прав на место (благодаря другому 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.
#++
Кредит для:
Ответ 2
Ruby предоставляет другой способ обработки STDIN: флаг -n. Он рассматривает всю вашу программу как находящуюся внутри цикла над STDIN (включая файлы, переданные как аргументы командной строки). См. следующая 1 строка 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
Я не совсем уверен, что вам нужно, но я бы использовал что-то вроде этого:
#!/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!
Ответ 4
Что-то вроде этого возможно?
#/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
Ответ 5
while STDIN.gets
puts $_
end
while ARGF.gets
puts $_
end
Это вдохновляет Perl:
while(<STDIN>){
print "$_\n"
}
Ответ 6
Быстро и просто:
STDIN.gets.chomp == 'YES'
Ответ 7
Я добавлю, что для использования ARGF
с параметрами вам нужно очистить ARGV
до вызова ARGF.each
. Это связано с тем, что ARGF
будет обрабатывать что-либо в ARGV
как имя файла и сначала читать строки.
Вот пример реализации "tee":
File.open(ARGV[0], 'w') do |file|
ARGV.clear
ARGF.each do |line|
puts line
file.write(line)
end
end
Ответ 8
Я делаю что-то вроде этого:
all_lines = ""
ARGV.each do |line|
all_lines << line + "\n"
end
puts all_lines
Ответ 9
Кажется, что большинство ответов предполагают, что аргументами являются имена файлов, содержащие контент для catdd для 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