注意: |
ここで扱うスクリプトは,一度に多量のファイル・ディレクトリを作成・削除する操作を含んでいるので,よく理解しないで実行すると危険なので注意すること。 処理用のディレクトリを作成し,そのディレクトリでスクリプトを実行したり,ファイル・ディレクトリのコピーを作り,そのコピーを処理対象にしたりすると,比較的安全である。 無限ループに陥るなどした場合には,早めにスクリプトを強制終了する ( cntrl + c )。 |
移動: chdir ディレクトリ名 作成: mkdir ディレクトリ名, パーミッション 削除: rmdir ディレクトリ名
ディレクトリを作成する際に指定するパーミッションは,0744 のように,先頭に 0 を付けた8進数で表わす。(cf. アクセス権の設定)
次のスクリプトを順番に実行し,結果を確認しなさい。(temp という名前のディレクトリ・ファイルがないディレクトリで実行すること。)
1. % perl -e 'mkdir "temp", 0744; system "ls -l"' 2. % perl -e 'system pwd; chdir "temp"; system pwd' 3. % perl -e 'chdir "temp"; system pwd; chdir ".."; system pwd' 4. % perl -e 'rmdir "temp"; system "ls -l"'
-e ファイル/ディレクトリが存在する -f 通常のファイル -d ディレクトリ -T テキストファイル -B バイナリファイル
適当なディレクトリに移動し,以下のスクリプトを実行せよ。演算子部分とファイル名部分を変更し実行し,結果を確認しなさい。
% perl -e 'if (-e "aesop.txt") { print "yes\n" } else { print "no\n" }'
ファイルやディレクトリの一覧を取得するには,次のような方法が考えられる。(例に挙げたのは,ディレクトリ data 内の,拡張子が txt であるファイルの一覧を配列 @files に代入する方法。)
@files = <data/*.txt>;
@files = glob ("data/*.txt");
opendir (DIR, "data"); @files = grep {/\.txt$/} readdir DIR;
@files = split ("\n", `ls data | grep '.txt'`);
@files = split ("\n", `find data -name "*.txt" -print`);
1. % perl -e 'print (`ls data | grep '.txt'`)' 2. % perl -e 'print (`find data -name "*.txt" -print`)' 3. % perl -e 'foreach $i (<data/*.txt>) { print "$i\n" }' 4. % perl -e 'foreach $i (glob "data/*.txt") { print "$i\n" }' 5. % perl -e 'opendir (DIR, "data"); foreach $i (grep {/\.txt$/} readdir DIR) { print "$i\n" }'
rename 旧ファイル名, 新ファイル名
------------------------------------------------------------ % echo "" > temp.txt; ls temp.txt % perl -e 'rename "temp.txt", "empty.txt"'; ls empty.txt % ------------------------------------------------------------
---------------------------------------------------------------------- % ls voa 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 2-257721 2-257742 2-257765 2-257786 2-257813 2-257835 % % perl -e 'foreach $i (<voa/*>) { rename $i, "$i.txt" }' % ls voa 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 2-257730.txt 2-257761.txt 2-257793.txt 2-257824.txt % % perl -e 'foreach $i (<voa/*.txt>) { $i=~/(.+)\.txt$/; rename $i, $1 }' % ls voa 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 2-257721 2-257742 2-257765 2-257786 2-257813 2-257835 ----------------------------------------------------------------------
拡張子 .txt を .html に変更する ------------------------------------------------------------ @filenames = glob ("*.txt"); foreach $i (@filenames) { $i =~ s/\.txt$//; rename "$i.txt", "$i.html"; } ------------------------------------------------------------
次のスクリプトは,「対象のファイルがあるディレクトリ」・「変更前の拡張子」・「変更後の拡張子」をコマンドラインで指定できるようにしたもの。(少し手を入れれば,拡張子の削除などもできるようになる。)
% perl chext.pl data txt html chext.pl ------------------------------------------------------------ die "USAGE: chext.pl dir old_ext new_ext\n" unless ($ARGV[2]); foreach $i (glob "$ARGV[0]/*.$ARGV[1]") { $i =~ s/\.$ARGV[1]$//; rename "$i.$ARGV[1]", "$i.$ARGV[2]"; } exit; ------------------------------------------------------------
次のように,桁数が3桁に揃うようにファイル名を変更するスクリプト。
1.txt, 2.txt, ... 10.txt, 11.txt, ... 100.txt, 101.txt ↓ 001.txt, 002.txt, ... 010.txt, 011.txt, ... 100.txt, 101.txt
same_num_of_digits.pl ------------------------------------------------------------ foreach $i (grep {/^\d+\.txt$/} glob "*.txt") { ($num, $rest) = $i =~ /^(\d+)(\.txt)/; $new = sprintf "%03d%s", $num, $rest; rename $i, $new; } exit; ------------------------------------------------------------
ハイフンに続けて2桁の連番を付けることで,既存のファイル名と重複しないファイル名にするスクリプト。ブロック部分を他のスクリプトの一部として埋め込むことを想定しているので,$temp, $num は my によってブロック内でのみ有効な変数としている。
------------------------------------------------------------ $file = '1.txt'; { my ($temp, $num); $temp = $file; while (-e $temp) { $num++; $temp = sprintf "%s-%02d", $file, $num; } $file = $temp; } open (OUT, ">", $file); ------------------------------------------------------------
重複しなければファイル名はどのようなものでもいい場合には,time 関数の返り値をファイル名とすることが考えられる。(この場合,ファイル名が作成時の時刻も表わしているので,ファイル名でソートすると自動的に作成順になるというメリットもある。)
time は秒数を返り値として返す。1秒以下は区別されないので,次のスクリプトでは,ファイル名が重複している場合には,一秒後に再度実行するようにしている。(一秒に一つしかファイルは作成されない。)
------------------------------------------------------------ $file = time . '.txt'; while (-e $file) { sleep 1; $file = time . '.txt'; } ------------------------------------------------------------ ------------------------------------------------------------ #上のスクリプトを do を使って書き換えたもの do { $file = time . '.txt' } while (-e $file and sleep 1); ------------------------------------------------------------
次のスクリプトを実行すると,10個の空のファイルが作成される。
------------------------------------------------------------ for ($count = 0; $count < 10; $count++) { do { $file = time . '.txt' } while (-e $file and sleep 1); open (OUT, ">", $file); } exit; ------------------------------------------------------------
次のスクリプトでは,同じ時間の場合は連番を付けて区別するので,一秒間に複数のスクリプトが作成できる。連番の桁数は一秒間に作成されうるファイルの数を考えて変える。
------------------------------------------------------------ for ($count = 0; $count < 100; $count++) { do { $file = time . (sprintf "-%03d", ++$num) . '.txt' } while (-e $file); open (OUT, ">", $file); } exit; ------------------------------------------------------------
% perl lsFiles.pl data lsFiles.pl ------------------------------------------------------------ #!/usr/bin/perl if ($ARGV[0] eq '/') { exit; } elsif ($ARGV[0]) { $rootdir = $ARGV[0]; } else { $rootdir = '.'; } @dirs = ($rootdir); while ($dir = shift @dirs) { @list = glob ("$dir/*"); push (@dirs, grep {-d} @list); push (@files, grep {-f} @list); } foreach $file (sort @files) { print "$file\n"; } exit; ------------------------------------------------------------
指定されたディレクトリの構成が次のようになっている (大文字はディレクトリ,小文字は普通のファイル) とすると,各段階における @dirs, @list, @files の内容は下の表のようになる。1は while ループの前の状態,8は後の状態である。
A┬b ├c └D┬e ├F─h └G┬I┬k │ └l └J─m
@dirs | @list ($dir/*) | @files | |
1 | A | ||
2 | A ←shift | A/b A/c A/D |
+ A/b + A/c |
3 | A/D ←shift | A/D/e A/D/F A/D/G |
A/b, A/c + A/D/ |
4 | A/D/F ←shift A/D/G |
A/D/F/h | A/b, A/c, A/D/e + A/D/F/h |
5 | A/D/G ←shift | A/D/G/I A/D/G/J |
A/b, A/c, A/D/e, A/D/F/h |
6 | A/D/G/I ←shift A/D/G/J |
A/D/G/I/k A/D/G/I/l |
A/b, A/c, A/D/e, A/D/F/h + A/D/G/I/k, A/D/G/I/l |
7 | A/D/G/J ←shift |
A/D/G/J/m | A/b, A/c, A/D/e, A/D/F/h, A/D/G/I/k, A/D/G/I/l + A/D/G/J/m |
8 | A/b, A/c, A/D/e, A/D/F/h, A/D/G/I/k, A/D/G/I/l, A/D/G/J/m |
ディレクトリを指定すると,その下にあるテキストファイルでキーワードを含むものを一覧表示する。上のスクリプト (lsFiles.pl) と違って,テキストファイルを配列に入れずに処理している。ソートなどの処理をする必要がない場合,ファイルの数が配列に収まりきらなくなるほど大きくなる場合などには,配列に入れずに一つ一つ処理するようにするとよい。
% perl findFiles.pl data "Japan" findFiles.pl ------------------------------------------------------------ #!/usr/bin/perl $keyword = $ARGV[1]; $keyword or exit; if ($ARGV[0] eq '/') { exit; } elsif ($ARGV[0]) { $rootdir = $ARGV[0]; } else { $rootdir = '.'; } @dirs = ($rootdir); while ($dir = shift @dirs) { @list = glob ("$dir/*"); foreach $ i (@list) { if (-d $i) { push (@dirs, $i); } elsif (-T $i) { open (IN, "<", $i); $/ = undef; $text = <IN>; print "$i\n" if ($text =~ m/$keyword/i); } } } exit; ------------------------------------------------------------