Kick Out the World

技術的なメモとかポエムを書きます。

Perlで進捗表示的なもの

CLIツールを書くと、結果の出力はファイルにする時に進捗具合を知りたいということが時々ある。

進捗の度合いを標準出力に出せば良い話だけど、Perlでの実現方法をググると、ハマるケースがあるようだ。

結論だけ言うと、Perlのバッファリングの仕様のようで、オートフラッシュを有効にすれば良いとのこと。 ということで実際に確認。

普通に書いて、行バッファリングされるパターン(失敗)

#!/usr/bin/env perl

use strict;
use warnings;

for (1..10) {
    print '.' x $_ . "\r";
    sleep 1;
}
print "\n";

f:id:stc1988:20150306232916g:plain

オートフラッシュを有効にするパターン(成功)

#!/usr/bin/env perl

use strict;
use warnings;

$| = 1; #オートフラッシュを有効にする
for (1..10) {
    print '.' x $_ . "\r";
    sleep 1;
}
print "\n";

f:id:stc1988:20150306234603g:plain

というところで、実現方法が確認できたので、進捗表示の簡単な関数を書いた。

#!/usr/bin/env perl

use strict;
use warnings;
use Time::HiRes qw/usleep/;

#進捗表示関数 => 現在の値と最大値を渡すことで進捗率に応じた状態を表示する
sub update_progress {
    my $progress = ($_[0] / $_[1]) * 100 / (100/50);
    print '.'x$progress . "\r";
}

my $max = 1000;
print "S" . " "x48 . "E\n";
$| = 1;

for my $current (1..$max) {
    update_progress($current, $max);
    usleep 10_000;
}
print "\n";

f:id:stc1988:20150307001126g:plain

進捗率がモリモリ更新されるようになりましたヽ( ´ ∇ ` )ノ