Corion hit the nail on the head.

The brief answer is -- make your standard output (STDOUT) flush immediately. To do so, add this line near the beginning of your script (before doing any print statments):

$| = 1;

The corresponding section from the article Corion linked to is the one entitled "Disabling Inappropriate Buffering", where it talks about making the "filehandle hot".

If you have use for a really fancy ascii-oriented progress bar, here is something I wrote that I've found useful in a lot of different applications:

# # progress_bar # # Input: $1 - A message to display with the progress bar. It can co +ntain # any of the following special 3-character strings, each + of which # will be converted to the following value: # # <b> - the progress bar itself # <c> - the current count # <p> - the percentage finished # <r> - estimated remaining time # <t> - the total count # # $2 - A total count # $3 - (optional) The 'done' symbol (default is '@') # $4 - (optional) The 'todo' symbol (default is '-') # # Output: A closure that takes a count, and updates the progress bar + based # on its value. When the progress bar is done, it should be + called # with no arguments, to show that the progress is complete - +and- to # print a final newline. ## sub progress_bar { my ($msg, $total, $done_sym, $todo_sym) = @_; ($total || 0) or fatal("total can NOT be zero/undefined!"); $done_sym ||= '@'; $todo_sym ||= '-'; $| = 1; my $start = time(); my $last = $start; my $remain = "???"; my $b_left = ($msg =~ /<r>/)? 1: 0; my $c_prog = sub { my ($count) = @_; my $b_done = defined($count)? 0: 1; $b_done and $count = $total; ($count > $total) and $count = $total; my $pcnt = sprintf "%6.2f", 100.0 * $count / $total; my $new_msg = $msg; # Calculate estimated remaining time my $time = time(); my $dtime = $time - $start; if ($b_done) { $remain = "Finished"; } elsif ($b_left and $count and $dtime and $time - $last > 3) +{ $last = $time; my $rate = ($count / $dtime); my $nsec = int(($total - $count) / $rate); my $hr = my $min = 0; if ($nsec > 3600) { $hr = int($nsec / 3600); $nsec -= 360 +0 * $hr } if ($nsec > 60) { $min = int($nsec / 60); $nsec -= 60 +* $min } if ($hr) { $remain = sprintf "%02d:%02d:%02d", $hr, $min, $nsec; } elsif ($min) { $remain = sprintf "%02d:%02d", $min, $nsec; } else { my $s = (1 == $nsec)? "": "s"; $remain = "$nsec second$s"; } } $new_msg =~ s/<c>/$count/g; $new_msg =~ s/<p>/$pcnt/g; $new_msg =~ s/<t>/$total/g; $new_msg =~ s/<r>/$remain/g; my $len = 79 + 3 - length($new_msg); my $ndone = int($len * $count / $total); my $ntodo = $len - $ndone; my $bar = ($done_sym x $ndone) . ($todo_sym x $ntodo); $new_msg =~ s/<b>/$bar/; print "$new_msg\r"; $b_done and print "\n"; }; return $c_prog; }

You can call it like this ... let's say you were processing a bunch of files, and wanted progress indication for each file processed:

use strict; use warnings; my @files = ( 'some', 'list', 'of', 'files' ); my $nfiles = @files; my $nhandled = 0; my $c_prog = progress_bar("File #<c> of <t> [<p>%] <b>", $nfiles); foreach my $file (@files) { do_something_with_this_file($file); $c_prog->(++$nhandled); } $c_prog->();

Note that you don't want to print anything while the progress bar is displaying, or it will disrupt the progress bar's output. :)

Subroutine do_something_with_this_file left as an exercise to the reader.


s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

In reply to Re: Real Time Progress Bar in console by liverpole
in thread Real Time Progress Bar in console by westrock2000

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.