find.rb

#find -x -n pattern filename, ...
  
  #プログラムの設定
  SelfName = "find"
  Version = "0.0.0"
  Usage = "Usage: #{SelfName} [-xn options] [filename]"
  
  #オプションの設定
  require 'optparse'
  mode_flags = {}
  opt_parser = OptionParser.new
  opt_parser.program_name = SelfName
  opt_parser.version = Version
  opt_parser.banner = Usage
  opt_parser.on("-x", String, /.*/, "show NOT-matched lines"){|v|
    mode_flags[:except] = true
  }
  opt_parser.on("-n", String, /.*/, "show lines with it's number"){|v|
    mode_flags[:lineno] = true
  }
  
  #コマンドラインをパース
  begin
    opt_parser.parse!(ARGV)
    raise(RuntimeError, "pattern not directed") if ARGV.empty?
    pattern = ARGV.shift
  rescue => ex
    $stderr.puts "Error --- #{ex.message}"
    exit(1)
  end
  
  
  #パターン検索本体
  def find_ptn(f, ptn="", modes={}, withfname=false, out_io=$stdout)
      f.each do |line|
        found = (/#{ptn}/ =~ line) ? true : false
        found ^= modes[:except]
        next unless found
        line.chomp!
        out = ""
        out << sprintf("%4d ", f.lineno) if modes[:lineno]
        out << line
        out << "  (#{f.path})" if withfname
        out_io.puts out
      end
  end
  
  
  #パターン検索開始
  if (ARGV.empty?)
    find_ptn($stdin, pattern, mode_flags)
  else
    begin
      if (ARGV.size == 1)
        File.open(ARGV[0]) do |f|
          find_ptn(f, pattern, mode_flags)
        end
      else
        until ARGV.empty?
          File.open(ARGV.shift) do |f|
            find_ptn(f, pattern, mode_flags, true)
          end
        end
      end
    rescue => ex
      $stderr.puts "Error: #{ex.message}"
      retry
    end
  end