Ruby版findコマンド - rfind

どうもfindコマンドは難しすぎて頭の悪い俺には覚えられん。ここは慣れ親しんだRubyで。
今まで何人の人がやったかわからないけど俺版を瞬時にでっちあげた。

#!/usr/bin/env ruby
# Ruby version of `find'
require 'pathname'
require 'rubygems'
require 'active_support/core_ext/numeric'

class PathnameExt < Pathname
  def =~(other)
    to_s =~ other
  end
end

def rfind(expr, *paths)
  rfind(expr, *STDIN.read.split(/\r?\n/)) if paths.empty?
  
  paths.each do |path|
    begin
      _ = PathnameExt.new path
      puts path if _.instance_eval(expr)
    rescue
    end
  end
end

if !ARGV[0] or ARGV[0]=='--help'
  puts "Usage: rfind expr [files]

expr is Ruby expression which _ is Pathname object with extension,
"
else
  rfind *ARGV
end

純粋なfindというわけではなく、実際は条件式に一致するファイルを絞り込むコマンド。

rfind RUBY_EXPRESSION [FILES]

のように使う。FILESのうち、RUBY_EXPRESSIONの条件を満たすもののみ表示する。FILESが与えられない場合は標準入力から読み込む。

使いやすいようにactive_supportの力でN.days.agoなどの表記が使えるようになっている。さらに、ファイル名の正規表現マッチのために =~ が使えるようになっている。

追記:instance_evalを使うことでなるべく_を省略できるようにしてみた。

3日以内に更新されたファイル・ディレクトリを取得するには、

$ rfind '_.mtime > 3.days.ago' *
$ find | rfind '_.mtime > 3.days.ago'
$ find | rfind 'mtime > 3.days.ago'

拡張子がtxt以外のファイルを取得するには、

$ find | rfind '_.file? and _ !~ /\.txt$/'
$ find | rfind 'file? and _ !~ /\.txt$/'

まぁこれくらいのコードならRuby流に「ソースがドキュメント」ということで(笑)