http://qs321.pair.com?node_id=396839

Texan has asked for the wisdom of the Perl Monks concerning the following question:

I am new to Perl, so be kind. I am trying to generate a progress bar. I need it to be only console based. I think I have the theory worked out, but cannot get the end result. I know that I start with a number and I have the max number but, how do I get the system to generate the progress bar? I am looking for a simple:
********33%
type of bar. But I am willing to use any code willingly given. Thanks

Replies are listed 'Best First'.
Re: Progress Bar
by tachyon (Chancellor) on Oct 06, 2004 at 02:33 UTC

    You might like wget style progress bar. Alternatively Super Search for 'progress bar' to turn up many other implementations.

    do{ progress_bar( $_, 100, 25, '=' ); sleep 1 } for 1..100; sub progress_bar { my ( $got, $total, $width, $char ) = @_; $width ||= 25; $char ||= '='; my $num_width = length $total; local $| = 1; printf "|%-${width}s| Got %${num_width}s bytes of %s (%.2f%%)\r", $char x (($width-1)*$got/$total). '>', $got, $total, 100*$got/ +$total; }

    cheers

    tachyon

Re: Progress Bar
by giulienk (Curate) on Oct 06, 2004 at 07:10 UTC
    Another option would be using Term::ProgressBar: i used it in the past and it's pretty easy and complete.


    $|=$_="1g2i1u1l2i4e2n0k",map{print"\7",chop;select$,,$,,$,,$_/7}m{..}g

Re: Progress Bar
by tmoertel (Chaplain) on Oct 06, 2004 at 03:14 UTC
    (Updated: Something bad happened to the code portion during cut-and-paste to the site. This is now fixed.)

    Here's a quick bit of code that provides a simple, object-oriented way to draw progress bars. To use it, just create a progress bar like so:

    my $bar = ProgressBar->new( width => 40 );
    (Here, our bar will be 40 characters wide.) Then, to draw the bar, just pass in the current count of completed tasks and the total number of tasks:
    $bar->draw( 3, 10 );
    So, in the above example, we have completed 3 of 10 tasks and the following would be drawn:
    ============ 30%
    A couple of points:
    • If the total number of tasks is fixed, you can provide it at the time you create the progress bar via the max_val parameter and omit it in calls to the draw() method.
    • The code works properly for progress bars that go forward, backward, or both. (See the demo.)

    Here's the code:

    #!/usr/bin/perl -w { # TGM 2004-10-05 # Progress bar code package ProgressBar; use Class::Struct width => '$', portion => '$', max_val => '$'; use List::Util qw( min ); sub draw { local $| = 1; my ($self, $x, $max_val) = @_; $max_val ||= $self->max_val; my $old_portion = $self->portion || 0; my $new_portion = int( $self->width * $x / $max_val + 0.5 ); print "\b" x ( 6 + $self->width - min( $new_portion, $old_portion ) ) if defined $self->portion; print "=" x ( $new_portion - $old_portion ), " " x ( $self->width - $new_portion ), sprintf " %3d%% ", int( 100 * $x / $max_val + 0.5 ); $self->portion( $new_portion ); } 1; } # DEMO my $pb = ProgressBar->new( width => 40, max_val => 10 ); # show progress 0 to 100% and then back down to 0% again do { $pb->draw( $_ ) ; sleep 1 } for 0 .. 10; do { $pb->draw( 9 - $_ ); sleep 1 } for 0 .. 9; print "\n";
    Hope this helps.

    Cheers,
    Tom

Re: Progress Bar
by ikegami (Patriarch) on Oct 06, 2004 at 02:36 UTC
    sub flush { my $h = select($_[0]); my $a=$|; $|=1; $|=$a; select($h); } sub show_progress { my ($progress) = @_; my $stars = '*' x int($progress*10); my $percent = int($progress*100); $percent = $percent >= 100 ? 'done.' : $percent.'%'; print("\r$stars $percent"); flush(STDOUT); } show_progress(1/4); sleep(1); show_progress(2/4); sleep(1); show_progress(3/4); sleep(1); show_progress(4/4);
Re: Progress Bar
by cosimo (Hermit) on Oct 06, 2004 at 10:53 UTC
    Another, totally different, perhaps "strange", approach could be based on Smart::Comments...

      I agree with this suggestion. I saw Damian's presentation which touched on this and it was really quite impressive.

      Have you seen the author/maintainers for that code? Damian, Autrijus, and Ingy. Gods, talk about a trifecta of Perfect Perl Prowess!

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

      Cheers for this suggestion, have never come across that module before and it looks perfect. I like to write lots of debugging friendly code in my scripts and have been using trailing "if $debug=1;" or similar. Smart::Comments makes all that so much nicer and neater.