23 Sep 2009

Wget like progress bar in console

Some time ago I was writing about notifying user that our software does not hang out, today I will also write about this. It is easy to create progress bar, and there is a numerous modules done (Oreily.com). But creating a simple progress bar (which looks like progress bar in wget) is pretty straight forward.

Output with detailed progress

Warning: This is only example after each execution of progressBar "\n" is inserted!. In final code this will be one animating line!
johny@jambia:~$ perl pgbar.pl 
Starting Hello
[i] Hello |>                                                                     | 0 of 10 (  0%)
[i] Hello |======>                                                               | 1 of 10 ( 10%)
[i] Hello |=============>                                                        | 2 of 10 ( 20%)
[i] Hello |====================>                                                 | 3 of 10 ( 30%)
[i] Hello |===========================>                                          | 4 of 10 ( 40%)
[i] Hello |==================================>                                   | 5 of 10 ( 50%)
[i] Hello |=========================================>                            | 6 of 10 ( 60%)
[i] Hello |================================================>                     | 7 of 10 ( 70%)
[i] Hello |=======================================================>              | 8 of 10 ( 80%)
[i] Hello |==============================================================>       | 9 of 10 ( 90%)
[i] Hello |=====================================================================>|10 of 10 (100%)

Hello started

Output normal process bar

Warning: This is only example after each execution of progressBar "\n" is inserted!. In final code this will be one animating line!
johny@jambia:~$ perl pgbar.pl 
Starting Hello
[i] Hello |>                                                                             | (  0%)
[i] Hello |=======>                                                                      | ( 10%)
[i] Hello |===============>                                                              | ( 20%)
[i] Hello |=======================>                                                      | ( 30%)
[i] Hello |==============================>                                               | ( 40%)
[i] Hello |======================================>                                       | ( 50%)
[i] Hello |==============================================>                               | ( 60%)
[i] Hello |=====================================================>                        | ( 70%)
[i] Hello |=============================================================>                | ( 80%)
[i] Hello |=====================================================================>        | ( 90%)
[i] Hello |=============================================================================>| (100%)

Hello started

Usage of my subroutine

I have created subroutine, which helps me display progress of work done by script in simple way. Usage is also pretty straight forward, I think:
my $MAX_I = 10;
my $PROC_NAME="Hello";
print "Starting ".$PROC_NAME."\n";
for ( my $i=0 ; $i<=$MAX_I ; $i++) {
 print progressBar($PROC_NAME, $i, $MAX_I);#."\n";
 sleep 1;
}
print "\n".$PROC_NAME." started\n";

Source of subroutine progressBar

# wget-style progress bar subroutine
#
# Author: Tachyon (http://tachyon.perlmonk.org/)
# Modified: sinx (http://blog.0x1fff.com/)
# 
# Changes: Made usage of original subroutine 
#          more user friendly.
#
sub progressBar {
    my ( $info, $curr, $total ) = @_;

    $info = '[i] ' . $info.' ';
    my @termSize = split( /\s+/, qx{stty size} );

    # Use this if you want detailed process progress
    # my $proc     = sprintf( '%'.length($total).'s of %s (%3d%%)',
    #    $curr, $total, 100 * $curr / +$total );
    my $proc     = sprintf( ' (%3d%%)', 100 * $curr / +$total );
    
    # Add 3 for spaces "\r\n\s" and other
    my $barWidth = $termSize[1] - ( length($info) + length($proc) +3 );
    #$barWidth = 0 if $barWidth < 0; # something is wrong if < 0;
    my $bar = sprintf( "|%-${barWidth}s|",
        '=' x ( ( $barWidth - 1 ) * $curr / $total ) . '>' );

    return $info . $bar . $proc . "\r";
}

Features

  • Upon terminal resize, the screen will not be correctly repainted until the next scheduled update.

Bugs

  • If screen is smaller than "info" and percentage count - it will broke - screen size is not checked in this subroutine

Alternatives - lib-notify

If you are using Gnome environment, you can also notify user about finished jobs using libnotify. Getting lib-notify: apt-get install libnotify-bin.

Sending notify through libnotify

Warning: In Perl you have to invoke system() or qx{}
notify-send -u normal 
  -i /usr/share/icons/gnome/scalable/status/sunny.svg
  'Hello '${USER}', today will be fine day!'
Sample notification looks like this: More detailed instruction about lib-notify can be found in LinuxJournal

Alternatives - progress without percentage

This can be done very easily, I have discussed this in one of my previous blog posts - post and example is in polish and was created for C Programming Language, but code should be very easy to understand even if you don't know polish language.

No comments:

Post a Comment