Ruby小ネタ:ディレクトリ走査とパラメータ操作

Evernoteのデータ操作でちょっと疲れたので小ネタを。

前者はとにかくディレクトリ走査をしてファイル情報を表示すること。イメージとしては find コマンド。
後者は getopt と言いたいところなのだけど(インタフェース的に慣れてる)どうやらRubyでは非推奨らしいのでoptparseをgetoptっぽい使い方で。

ディレクトリ走査

あまり難し事は考えずに普通に再帰で組んでみた。

#!/usr/bin/ruby
# -*- coding: utf-8 -*-
#
# = ファイル走査の練習
#


#
# == ディレクトリを走査してファイル情報を表示
#
#
def list_dirs (path)
  Dir::foreach(path) { |name|
    next if name == "." or name == ".."

    # 操作が面倒なので絶対パスで確認
    puts name = File.expand_path(name, path)

    if FileTest::directory?(name) then
      # ディレクトリだったら再帰して検索
      list_dirs(name)
    end
  }
end


#
# - MAIN -
#

# パス指定が無ければエラー
if ARGV.size < 1 then
  abort "usage: #{$0} path.."
end

# 指定されたパスすべてを走査
ARGV.each { |path|
  puts path = File.expand_path(path)
  if FileTest::directory?(path) then
    list_dirs(path)
  end
}

基本的にはDir::foreachで回すだけ(list_dirs)で、そのループ内で適当に処理するだけで簡単に走査できる。

$ chmod +x list.rb
$ ./list.rb .
/Users/xxxx
/Users/xxxx/.DS_Store
/Users/xxxx/list.rb
/Users/xxxx/list.rb~
/Users/xxxx/test
/Users/xxxx/test/empty.dat
$ find `pwd`
/Users/xxxx
/Users/xxxx/.DS_Store
/Users/xxxx/list.rb
/Users/xxxx/list.rb~
/Users/xxxx/test
/Users/xxxx/test/empty.dat

あまり細かいテストはしていないのだけど、表示だけならだいたい find コマンドと同じことができてる。

パラメータ操作

Ruby 1.8.7 リファレンスマニュアルAll Libraries > library optparseを参考に、optparseで解析処理を作ってみる。
細かい処理はそのうち考えるとして、OptionParser::Arguableでとにかく簡単にできるように。

あまりネタも無いので、ls -a みたいなドットファイル(.DS_Storeなどの ‘.’で始まるファイル)を隠したり表示したりするオプションを組み込んでみる。

require 'optparse'
$params = ARGV.getopts("a")

とりあえずライブラリを読み込んで、解析処理を実行。ここでオプション “a” も設定する。

def list_dirs (path)
  Dir::foreach(path) { |name|
    next if name == "." or name == ".."

    # -a  Include directory entries whose names begin with a dot (.).
    next if /^\..*/ =~ name and !$params["a"]

    # 操作が面倒なので絶対パスで確認
    puts name = File.expand_path(name, path)

    if FileTest::directory?(name) then
      # ディレクトリだったら再帰して検索
      list_dirs(name)
    end
  }
end

追加したのは24-25行目のフィルタ処理だけなのだけど、それだけじゃわかりづらいかもしれないので関数単位で。
正規表現で引っかけてはじくようにしてるだけ。

先ほどのファイル走査だけを list.rb / このパラメータ操作を追加したものを list2.rb にして分けて保存。
実際に動かしてみるとこんな感じ

$ ./list.rb .
/Users/xxxx
/Users/xxxx/.DS_Store
/Users/xxxx/list.rb
/Users/xxxx/list2.rb
/Users/xxxx/test
/Users/xxxx/test/empty.dat
$ ./list2.rb -a .
/Users/xxxx
/Users/xxxx/.DS_Store
/Users/xxxx/list.rb
/Users/xxxx/list2.rb
/Users/xxxx/test
/Users/xxxx/test/empty.dat
$ ./list2.rb .
/Users/xxxx
/Users/xxxx/list.rb
/Users/xxxx/list2.rb
/Users/xxxx/test
/Users/xxxx/test/empty.dat

list2.rbは -a オプションの有無で想定した通りの動作ができてる!

最後にlist2.rbのフルソースを( ´ ▽ ` )ノ

#!/usr/bin/ruby
# -*- coding: utf-8 -*-
#
# = ファイル走査の練習
#
#  Authors:: Ken AKASHI <ks at ksworks.org>
#  Version:: 2011-11-09
#  License:: NYSL Version 0.9982
#  Copyright:: Copyright (C) ksworks, 2011. All rights reserved.
#

require 'optparse'
$params = ARGV.getopts("a")


#
# == ディレクトリを走査してファイル情報を表示
#
#
def list_dirs (path)
  Dir::foreach(path) { |name|
    next if name == "." or name == ".."

    # -a  Include directory entries whose names begin with a dot (.).
    next if /^\..*/ =~ name and !$params["a"]

    # 操作が面倒なので絶対パスで確認
    puts name = File.expand_path(name, path)

    if FileTest::directory?(name) then
      # ディレクトリだったら再帰して検索
      list_dirs(name)
    end
  }
end


#
# - MAIN -
#

# パス指定が無ければエラー
if ARGV.size < 1 then
  abort "usage: #{$0} [-a] path.."
end

# 指定されたパスすべてを走査
ARGV.each { |path|
  puts path = File.expand_path(path)
  if FileTest::directory?(path) then
    list_dirs(path)
  end
}