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
以下は、あいまいな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.
#++
クレジット:
Rubyは、STDINを処理する別の方法を提供します。-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
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!
おそらくこのような何か?
#/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'
私はこのようなことをします:
all_lines = ""
ARGV.each do |line|
all_lines << line + "\n"
end
puts all_lines
パラメーターで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
ほとんどの答えは、引数がstdinにcat'dされるコンテンツを含むファイル名であると仮定しているようです。以下はすべて引数として扱われます。 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