#!/usr/bin/perl -w # Strict use strict; use warnings; # User-defined my $total = 10_000; # Main program my $i; print "Progress (of whatever)\n"; my $meter = new meter($total); for (my $i = 0; $i < $total; $i++) { $meter->update($i); # Call your code here &my_subroutine(); } $meter->update(); print "Done!\n"; # Subroutines sub my_subroutine() { # For test purposes, sleep for a random interval of milliseconds my $nmilli = int(rand(1010) / 1000); select(undef, undef, undef, $nmilli); } package meter; # Libraries use Carp; # # Inputs: $1 ... the meter object # $2 ... total value (when reached, the meter will register 100%) # # Description: Creates a "visual" meter, which displays an ascii picture # representing the progress towards a total count. # sub new() { my ($proto, $total) = @_; ($total || 0) or croak "Invalid 'total' in object 'meter'"; # User-configurable my $width = 64; # Total meter width my $blank = '-'; # Blank symbol my $done = '*'; # Progress symbol my $interval = int($total / $width); my $class = ref($proto) || $proto; my $self = { 'total' => $total, 'interval' => $interval, 'width' => $width, 'blank' => $blank, 'done' => $done, }; bless $self, $class; $self->update(0); return $self; } # # Inputs: $1 ... the meter object # $2 ... (optional) the progress count (if undefined, sets the # count to the total, and outputs the final newline). # # Description: Updates the meter using the given count (which should be # a minimum of zero, and a maximum of $this->{'total'}). # sub update() { my ($this, $count) = @_; my $done = defined($count)? 0: 1; my $total = $this->{'total'}; defined($count) or $count = $total; return unless ($count == $total || 0 == ($count % $this->{'interval'})); my $pct = 100 * $count / $total; my $width = $this->{'width'}; my $size = int($width * $count / $total); my $str0 = $this->{'done'} x $size; my $str1 = $this->{'blank'} x ($width - $size); select((select(STDERR), $| = 1)[0]); printf STDERR " %6.2f%% [%s%s]\r", $pct, $str0, $str1; $done and print STDERR "\n"; } 1;