Ruby : ARGF の使い方

作成日 : 2021-04-10
最終更新日 :

説明

スクリプト言語のプログラムでは、指定した引数をすべてファイル名とみなし、 それらのファイルを連結した一つの仮想ファイルとみなすと便利なことがある。 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 の使い方


MARUYAMA Satosi