perlのreaddirでのファイル取得順序がバラバラ?
バッチ処理で特定のディレクトリ以下のファイルをDBに取り込みをしていたのだが、 取り込む順序があるのにも関わらず、perl の readdirで得られたファイルの順序で取り込みをしていて不具合が発生していた。
perlのreadirの仕様はどうなってるのか?
そもそも取り込み順にソートしていないことが問題ではあるのだが、一体perlのreaddirはどういった順序でファイルを取得しているのか、試しにサンプルプログラムで確認してみた。
test.pl
#!/usr/bin/perl $dir = "/tmp/"; opendir(DIR, $dir); @files = grep { !m/^(\.|\.\.)$/g } readdir DIR; close DIR; foreach $file ( @files ) { print $file."\n"; }
ファイルを表示してみるとタイムスタンプ順もファイル名順でもなく、よくわからない。
ファイルを作ってテスト
試しに以下のコマンドでテストファイルをtouchして上記のテストプログラムを実行すると、
$ mkdir /tmp/test $ for i in `seq -w 1 10`;do touch /tmp/test/hogehoge.$i;done $ ./test.pl hoge_08.txt hoge_10.txt hoge_09.txt hoge_07.txt hoge_04.txt hoge_06.txt hoge_02.txt hoge_01.txt hoge_05.txt hoge_03.txt
んー、バラバラになるなぁと、ファイル名変えたりして何度かテストしていると、
hogehoge.10 hogehoge.09 hogehoge.08 hogehoge.07 hogehoge.06 hogehoge.05 hogehoge.04 hogehoge.03 hogehoge.02 hogehoge.01
新しい順になったりと挙動がよくわからない。 調べてみたところ、ファイルシステムに準ずると言われていることもあるらしいが、perlの公式な仕様としては明確になっていないとのことだ。
というわけで、順序が大切なときはreaddirの取得順を当てにせずしっかりsortしよう。
perlで古い順にファイルをソートするには
my @sorted_files = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { my @st = stat "$dir/$_"; [ $_, $st[10] ] } @files;
こんな感じでstatした結果をsortする。
lsコマンドでミリ秒単位で古い順に表示するには
ls -alttr --full-time
-ttでミリ秒まで
-rで逆順ソートしてくれる
--full-time でミリ秒以下まで表示
参考にしたサイト