ログファイルを処理したいとかで、とあるディレクトリのファイル一覧がほしいときってありますよね!そんなときのための三題話。
opendir
入門書には必ず載ってるopendir。使い方は簡単。ディレクトリ名を入れて開くだけ。あとはopenと同じように開いたハンドルを読み出していくだけ!
opendir(DIR, $dname);
while (defined($fname = readdir(DIR))) {
print "$fname\n";
}
closedir(DIR);
実行したら、'.' (現在のディレクトリ)とか '..' (ひとつ上のディレクトリ)とかも入ってくるけど、単純に一覧がほしいときは簡単だね!
glob
opendirだととってくるファイル名は何も決められなかったけど、globを使ったら指定できるようになるよ!
たとえば、'accesslog*'ってのに当てはまるものだけがほしいときは
@fnames = glob("$dname/accesslog*");
とやれば配列に入ってくるよ。正規表現チックだけどシェルで'ls'とかやるときの表現なので注意が必要だね。でも、単純だけど便利だよね!
globの中にはスペース区切りでいくつでも指定できるし、シェルで機能する"*.{bz2,gz}"とかも使えるけど、マッチ指定のない文字列を入れたらそれもかえってくるので注意が必要だよ!
% perl -e 'my @temp = glob("*.{bz2,gz} x"); print join("\n", @temp) . "\n";'
wordpress-2.2.1.tar.gz
wp-2.3.2.tar.gz
wp-2.5.1.tar.gz
x
% ls x
ls: x: No such file or directory
File::Find::Rule
最後にモジュールを使ってみるよ!これまでより無駄に高機能だし、OSによってディレクトリの区切りが違う(Winは'\'、Unixは'/'、Macは':'とか)のを気にせず使えるよ!
use File::Find::Rule;
my $rule = File::Find::Rule->new;
$rule->file; # ファイルであるものを指定
$rule->name( '*.pm' ); # *.pmにマッチするもののみ
my @files = $rule->in( @INC );
これだけで、*.pmってファイルだけが配列でかえってくるよ!
条件を追加するときは'$rule->xxxx'の行を増やしていくだけだよ。たいていのファイルテスト演算子は->readableとかであるし、サイズ指定(->size())もあるし、->maxdepth()とか->mindepth()とかでディレクトリの深さも指定できるよ! File::Find::Ruleのオブジェクトをand/orできるから、複雑な条件でも対応できるよ!
my $rule = File::Find::Rule
$rule->any(
File::Find::Rule->name('*.pm'),
File::Find::Rule->size('<10k'),
File::Find::Rule->maxdepth(5)
);
・・・・・でも、だいぶ遅い。普通のときは、無名関数とか関数へのリファレンスが必要だけどFile::Findを使えばいいと思うよ!こっちは標準モジュールだしね!(ファイル数が多いと遅いけど。。。)
もっとも、この系統のモジュール、File::Finderとかいろいろあるけど、何が一番いいんだろう。



Leave a comment