録画ファイルを自動的に移動したりscpしたりするプログラムを書いてて、ハマったのでその話。
次のようなプログラムを書いていました。
@config = ( { "re" => "filename", "rule" => { "BS211" => "/export1", "GR20" => "/export2", }, }, ); foreach my $elem (@config) { my $re = $elem->{re}; if ($filename =~ /${re}/) { # check channel my $rule = $elem->{rule}; while (my ($key, $value) = each %rule) { if ($key eq $channel) { move_to_dir($filename, $value); last; } } last; } }
(リファレンスとかデリファレンスは実際のプログラムとは違いますが、そこは本質ではない)
外側のループはforeachで、内側のループはwhile-eachで回していました(今にして思えばそれが問題の発見を遅らせた)。
で、この部分を無限ループで回して、ファイルが出来るごとに移動しようとしたんです。
ところが、「ルールにマッチしているはずなのに、なぜか移動できない」という事態が多発したので、いろいろ調べた結果、衝撃の事実が。
……あぁ、確かに、うまくいかなかったのは、「直前に、同じルールにマッチする、チャンネル違いのデータが移動された場合」だった。
ということで、この挙動によって、内側のループ(チャンネル判定)が途中から始まってしまったために、チャンネルの判定がマッチせず、移動されない場合が発生したのでした。
解決策として、while – eachを使わず、foreach – keys を使うことで解決、と。