Linux でファイルのリストを見るには ls コマンドを使いますが、Perl では glob というファンクションがあります。
@files = glob ("*.gif");とすれば、*.gif というパターンに一致するファイル名を配列 @files1 に格納してくれます。個々のファイル名を取りだすには
for $file (@files){ print $file, "\n"; }とすればいいわけです。
異なったパターンをファイルを一括して得たい場合は
@files1 = glob ("*.gif"); @files2 = glob ("*.jpg"); @files3 = glob ("*.png"); @files = (@files1, @files2, @files3);とすれば、HTML で使うことのできる画像ファイルを得ることができます。
これから作ろうとしているのは、JPG ファイルに連番をつけて整理するプログラムです。デジタルカメラで撮った JPG ファイルを「人物」「物体」「風景」などのカテゴリーに分け、それぞれに連番をつけて整理しようというものです。glob で得られるファイル名はファイル名順でソートされていますので、連番はファイル名順で付けられることになります。
新しいファイル名は A234.jpg B045.jpg などと、「ファイル名」+「三桁の数字」+「拡張子」 とすることにしました。ですから、新しいファイル名を得るには、fukei.jpg などとなっているファイル名から .jpg 以前の部分得る必要があります。これには
@body = split /\./, $oldname;という式を使います。正規表現ではピリオド(.)はそのままでは別の意味になりますので、\ でキャンセルして \. と表します。これによって .jpg 以前の部分は @body という配列の最初、つまり $body[0] に入り、jpg は $body[1] に入ることになります。次の部分では @files = glob ("*.jpg") で得たファイル名から、古いファイル名と新しいファイル名を一度に取りだしています。
# 新しいファイル名を @newname に格納 $sum = 0; for $oldname (@files){ @body = split /\./, $oldname; if($number < 10){ $p_number = "00$number"; } elsif($number < 100){ $p_number = "0$number"; } else{ $p_number = $number; } $newfiles[$sum] = "$newname$p_number.$body[1]"; $sum++; $number++; }$number は、コマンドラインから初期値を得るようにするので、ここではわざと $number = 1 などと初期化していません。また、$number が 1 から 9 までは 001, 002, 003 など、$number が 10 から 99 までは 097, 098, 099 などと表示するようにするため、'0' をつけるようにしている部分もお見逃しなく。$sum は、ファイルが何個あったかを知るための変数で、ファイルの総計をカウントしてくれます。
これで system ("mv $oldname $newfiles[$count]"); としてやれば、ファイル名を変換してくれるのですが、$oldname と $newfiles[$count] が同じ名前の場合、エラーが出ますので、あらかじめ、$oldname と $newfiles[$count] を比較しておいて、もし、同じファイル名があったら、終了して別のファイル名なり、開始番号なりを入力してやりなおさせるようにしておきました。これが、次の部分です。
# オリジナルのファイル名と新しいファイル名の比較 # 同じものがあれば作業をしない for $oldname (@files){ for $newname (@newfiles){ if($oldname eq $newname){ print "Found the same file name!\n"; exit(0); } } }
以上を一つにまとめたのが次のスクリプトです。
#!/usr/bin/perl # renames.pl # # 画像ファイルに連番をつけて名前を変更する # 開始番号の取得 if($ARGV[1] eq ""){ $number = 1; } else{ $number = $ARGV[1]; } # 画像ファイル名の取得 $newname = $ARGV[0]; if ($newname eq ""){ print "Input new file name [and start number].\n"; print "You can rename back by running <backnames>.\n"; exit (0); } # ファイル一覧の取得 # オリジナルのファイル名を @files に格納 @files = glob ("*.jpg"); # 新しいファイル名を @newname に格納 $sum = 0; for $oldname (@files){ @body = split /\./, $oldname; if($number < 10){ $p_number = "00$number"; } elsif($number < 100){ $p_number = "0$number"; } else{ $p_number = $number; } $newfiles[$sum] = "$newname$p_number.$body[1]"; $sum++; $number++; } # オリジナルのファイル名と新しいファイル名の比較 # 同じものがあれば作業をしない for $oldname (@files){ for $newname (@newfiles){ if($oldname eq $newname){ print "Found the same file name!\n"; exit(0); } } } # バックアップを backnames に保存する open OUT, ">backnames"; print OUT "#!/bin/bash\n"; # ファイル名の変換 $count=0; for $oldname (@files){ system ("mv $oldname $newfiles[$count]"); print OUT "mv $newfiles[$count] $oldname\n"; $count++; } close (OUT); # バックアップファイルに実行属性をつけて逆変換を可能にする system ("chmod +x backnames");
上記で、工夫したのは、
# バックアップを backnames に保存する open OUT, ">backnames"; ....(1) print OUT "#!/bin/bash\n"; ....(2) # ファイル名の変換 $count=0; for $oldname (@files){ system ("mv $oldname $newfiles[$count]"); print OUT "mv $newfiles[$count] $oldname\n"; ....(3) $count++; } close (OUT); # バックアップファイルに実行属性をつけて逆変換を可能にする system ("chmod +x backnames"); ....(4)の部分です。backnames というファイルを書き込みモードでオープンして(1)、これをシェルスクリプトにします(2)。逆変換ができるようにコマンドを書き込み(3)、最後にパーミッションを「実行可」にしておきます。こうすれば、「あっ、変換するんじゃなかった」と悲しい思いをすることなく、./backnames を実行すれば、もとに戻せるという、親切設計になっています。