サンプル3 大量のファイルを一気にリネームする

リスト4●MP3ファイルが入ったフォルダ名を取得して,新しいファイル名を付けるプログラム
図6●リスト4の実行結果。曲順と曲名だけを表したファイル名が付いていたが,「The Nightfly」というフォルダ名も付加したファイル名に変更した
リスト5●JPEGファイルのメタデータを参照して,撮影日ごとのフォルダに分類するプログ ラム
リスト6●二つのコード片の実行速度を比較するプログラム
図7●リスト6の実行結果。どちらのコード片の方がどれくらい速いかを表示する

 スクリプト言語を利用する大きな目的の一つとして,手間がかかる作業の自動化が挙げられるでしょう。例えば,たくさんあるファイルの名前を一つひとつ変更する作業はとても面倒です。そこで,標準モジュールの「File::Find」を使って,大量のファイルのファイル名を変更する方法を紹介します。このモジュールは,指定したフォルダ以下を探索しながら,指定した処理を実行させるものです。ファイルの探索などにも使えます。

 ここでは,アルバム名を付けたフォルダに入っているMP3ファイルの名前を一気に変更します。フォルダに入っているファイルには,もともと曲名がファイル名として付いています。これを「アルバム名 - 曲名.mp3」という具合に変更します。

 リスト4[拡大表示]がファイル名変更プログラムです。3行目の「use File::Find」という宣言で,findという関数が使えるようになります。findは,サブルーチンへの参照と,探索するフォルダを引数として受け取って,フォルダ内のすべてのファイルに対して順次サブルーチンを実行していきます。findの引数でサブルーチンを指定するときは,サブルーチンの名前の前に「¥」と「&」を付けます。探索するフォルダとして「$ARGV[0]」を渡します。これは,コマンドラインで指定する引数を参照する定義済み配列変数です。

 ファイル名の書き換えは,リストの中ほどにある「rename」サブルーチンが担当しています。まず,$File::Find::nameを使って,指定したフォルダのパスを取得します。取得したら,正規表現を使って拡張子が.mp3以外のファイルを排除します。「=~」は左辺の変数に対して正規表現がマッチするかどうかを確かめる演算子です。その後パス名を「/」で分割し,配列に入れます。「split」は指定した文字や正規表現で文字列を分割し,配列を返す関数です。

 ファイル名を付けるときは,配列からファイル名とフォルダ名を取り出して,二つを合成します。Windows環境でもパスの区切りには「¥」ではなく「/」を使うという点と,ファイル名を渡すときにシフトJISに変換する点に注意しましょう。実行すると,変換前のファイル名を一通り表示した後,変換後のファイル名を並べて表示します(図6[拡大表示])。

 ついでにもう一つ,ファイル整理に役立つプログラムを紹介しましょう。デジカメで撮影した画像データを日付ごとに整理するプログラムです。これは,画像(JPEG)データに埋め込まれている撮影日情報を取得して,撮影日ごとにフォルダを作り,そこにファイルを分類するというものです(リスト5[拡大表示])。

 このプログラムには「Image::MetaData::JPEG」モジュールを利用します。このモジュールは,JPEGのメタデータ(撮影日情報など)を読み出すモジュールです。ただし,このモジュールは標準のActivePerlには入っていないので,PPMからインストールしてください。「install Image-MetaData-JPEG」を実行すればインストールできます。

サンプル4 Perlコードの実行速度を測ってみよう

 Perlには「There,s More Than One Way To Do It.」というスローガンがあります。日本語に訳すと「やり方は何通りもある」という意味です。つまり,同じ目的を果たすプログラムでも,何通りもの書き方があるということです。どんなプログラミング言語にもそういう性質はありますが,Perlは特に際立っています。Perlの表現方法の多彩さを,自然言語になぞらえる人もいるくらいです。例えば文体を軽くも重くもできるし,あちこち省略した記法も使えます。

 このように書き方が自由なため,ルールにとらわれずに習得できるというメリットがあります。自然言語のように,片言でも何とかなってしまうのです。しかし,これには弊害もあります。書き手が文体や語彙(ごい)を統一しないと,とても読みにくいコードが出来上がってしまうのです。

 加えて,書き方によってプログラムの実行速度が変わることも珍しくありません。もともとスクリプト言語なので,実行速度はあまり重要ではないかもしれませんが,繰り返し処理部分などをできるだけ高速に処理させたい場合もあります。このような場面で書き方に迷ったら,標準モジュールである「Benchmark」を使ってコード片(一つのコード)の速度を計測するとよいでしょう。

 リスト6[拡大表示]は,2通りの書き方ができるコード片の実行速度を比較するプログラムです。どちらも100の2乗を2000万回計算します。「timethese」の第1引数は計算回数で,第2引数のハッシュで指定したコード片が,比較するコード片です。今回は,それぞれ2乗を表す記述である「$i * $i」と「$i ** 2」の二つを比較してみました。計算回数があまりに少ない場合は正確な結果が出ないと警告が出ます。どちらの計算でも,数秒かかるくらいに調整してください。コードの最後にある「cmpthese」は,結果を表(マトリクス)にしてそれぞれが何%高速なのかを示してくれます。

 cmptheseを使うには,冒頭のモジュール呼び出しをちょっと工夫しなければなりません。「use Benchmark」の後に「qw(:all)」を追加するのです。この部分は,どの関数を現在の名前空間にインポートするかを示しています。qw(:all)と記述すると,すべてをインポートすることになります。標準的な呼び出しではcmptheseをインポートできないのです。

 リスト6の実行結果(図7[拡大表示])を見ると,Method1($i * $i)が3秒,Method2($i ** 2)が5秒かかりました。「$i * $i」のほうが高速に動作するようです。2乗を3乗,4乗と変更するとまた違う結果になると思いますが,少なくとも2乗の場合はこのように書いたほうが速いようです。