ディレクトリの中身を再帰的に表示したい。linux だと find コマンドを使えば簡単です。しかしWindowsのFindコマンドがファイル内部を検索するものであり、Windowsでfind みたいなことを試みると、チョットめんどくさいのです。(WSHでも面倒)勉強のためなら再帰プログラムを再発明した方が良いけど、すぐ使いたいのでぱっぱと終らせた。
Rubyなら簡単にできました。
Linuxコマンドなら
$ find # sort の必要すらない.
Dir.glob を使う
#ピクチャディレクトリの中を見る Dir.glob '/users/takuya/Pictures/**/*' # => ['/users/takuya/Pictures/100MEDIA/IMAG0249.jpg', '/users/takuya/Pictures/100MEDIA/IMAG0252.jpg'] #カレントディレクトリ以下を再帰的に見る Dir.chdir '/users/takuya/Pictures' puts Dir.glob './**/*' # => ['./100MEDIA/IMAG0249.jpg', './100MEDIA/IMAG0252.jpg']
glob のオプションに '**/*' を書くと、再帰的を意味するそうです。
**/ ワイルドカード */ の0回以上の繰り返しを意味し、 ディレクトリを再帰的にたどってマッチを行います。 例えば, foo/**/bar は foo/bar, foo/*/bar, foo/*/*/bar ... (以下無限に続く)に対してそれぞれ マッチ判定を行います。
http://www.ruby-lang.org/ja/man/html/Dir.html
Find モジュールを使う
require 'find' inclue Find find('/users/takuya/pictures/'){|e| puts e } ##結果 ./100MEDIA/IMAG0249.jpg ./100MEDIA/IMAG0252.jpg
find の場合は必ずblock を取るので、block が無いと no block given になる。collection が戻ってこないのでチョット使いにくい
Dir.glob が使いやすい
Dir.glob を使うと、結果を配列で取得できます。だからソートが楽です。日付順ソートが簡単です。また『ある日付より前だけ』といったフィルタリングも簡ですね。
結果のソート例(Rubyマニュアルより)
Dir.glob("*").collect{|f| [File.mtime(f), f] }. sort{|a,b| b[0]<=>a[0] }.collect{|e| e[1] }とすると、カレントディレクトリの"."、".."以外のファイルを更新時間の 新しい順にソートした配列を返します。
http://www.ruby-lang.org/ja/man/html/FAQ_C1C8A4DFB9FEA4DFA5E9A5A4A5D6A5E9A5EA.html
2011-06-11追記 .htaccess が取得できない Dir::glob
.htaccess( dot files)に注意 、ドット始まりのファイルにはなぜかマッチしません
find なら.htaccess にもマッチするが
>> find('./event') {|e| puts e } ./event ./event/index.jsp ./event/form1.jsp ./event/.htaccess #=>.htaccessがある => nil
Dir::globだと.htaccess にはマッチしない
>> Dir.glob("./event/**/*"){|e| puts e} ./event/form1.jsp ./event/index.jsp => nil #=>.htaccessがない
dir::glob だと .gitとか .htaccess とか .bashrc とか見えないです.
これはピリオドにマッチしないのがfnmatch の基本動作だから正しい.
File::FNM_DOTMATCHで解決。
Dir::glob がピリオド(ドット)ファイルにマッチするようにするにはFile::FNM_DOTMATCHを使う。
.htaccess も取れる
>> Dir.glob("./event/**/*",File::FNM_DOTMATCH){|e| puts e} ./event/. ./event/.. ./event/.htaccess ./event/form1.jsp ./event/index.jsp => nil
今度はウマく取れます.が ".." "." というディレクトリを示すファイルまで取れちゃいました.
"..", "."は不要
ドットにマッチして欲しいけど ディレクトリは要らない
>> Dir.glob("./event/**/*",File::FNM_DOTMATCH).reject{|e| [".",".."].any?{|s| s== File::basename(e) } } => ["./event/.htaccess", "./event/form1.jsp", "./event/index.jsp"]
無理矢理だけれど、こんな感じ.