スクリプト言語のプログラムでは、指定した引数をすべてファイル名とみなし、 それらのファイルを連結した一つの仮想ファイルとみなすと便利なことがある。 Ruby では、そのような一つの仮想ファイルを ARGF というオブジェクトで操作する。
https://docs.ruby-lang.org/ja/latest/class/ARGF.html
によれば、
while line = ARGF.gets # 何かする end
は、次と同じように動作する:
while argv = ARGV.shift File.open(argv) {|file| while line = file.gets # do something end } end
この ARGF は便利だ。ついでに、ruby の起動オプションで -n を指定すれば、スクリプトとして、
# 何かする
だけ書けば、それだけでループが実現できて、さらに便利だ。
以上の操作は、複数のファイルから一つのファイルを選び、一つのファイルから各行を選ぶ、ということを繰り返している。 これは、テキストファイルを行単位で加工するのには都合がいい。 しかし、ファイルのテキストファイルをまるごと読み込んで、 1ファイルにつき情報を1行で出力するような用途には向いていない。 たとえば、wc という、ファイルの行数・単語数・文字数を出力するプログラムでは次のような出力が得られる:
$ file file1.html file2.html file3.html 5 23 59 file1.html 11 77 478 file2.html 48 123 998 file3.html 64 223 1535 合計
このようなことを実現するときには、ファイルは行単位でなく、一度に読み込めるのがいい。 以下、ファイル全体を操作する対象として、ファイルの文字列のサイズを表示することとする。 そう考えて、gets の代わりになるものがないか、しばらく悩んだ。結局、 gets にオプションを与えて次のようにすればいいことがわかった。
while argv = ARGV.shift File.open(argv) {|file| line = file.gets(rs = nil) puts line.size } end
gets のオプションについては次を参照:
https://docs.ruby-lang.org/ja/latest/method/ARGF=2eclass/i/gets.html
この rs = nil オプションができるなら、こうしてもいいはずだ。
while line = ARGF.gets(rs = nil) puts line.size end
Ruby のワンライナーとして書くとこうなるだろう。
$ ruby -e 'while line = ARGF.gets(rs = nil) do puts line.size end' file?.html
この rs = nil をスクリプトで書く代わりに Ruby の実行時オプションとすることもできる。
$ ruby -0777 -e 'while line = ARGF.gets do puts line.size end' file?.html
この -0777 というオプションは、rs = nil を意味している。次を参照:
https://docs.ruby-lang.org/ja/latest/doc/spec=2frubycmd.html
ARGF や line も省略できる。line を省略したので、代わりに $_ を使う。
$ ruby -0777 -e 'while gets do puts $_.size end' file?.html
さらに -n オプションを使うと、while ... end も省略できる:
$ ruby -0777 -ne 'puts $_.size' file?.html
めでたしめでたし。
まりんきょ学問所 > Rubyの浮き輪 > Ruby : ARGF の使い方