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

Good day seminarians. I have a script that processes a number of large JSON files and I would like to have a bar to track progress for each file. I've tried to implement one, as shown here on a pseudo-version of my code (to avoid distractions) like so:
use strict; use feature ':5.10'; use Term::ProgressBar; my @files = qw(30 50); foreach my $f (@files) { my $max = $f; my $progress = Term::ProgressBar->new({name => 'Processed', count +=> $max, remove => 1, ETA => 'linear'}); $progress->max_update_rate(1); $progress->minor(0); my $next_update = 0; foreach my $i (0..$max) { sleep 1; # represents stuff my script is actually processing $next_update = $progress->update($_) if $_ >= $next_update; } $progress->update($max) if $max >= $next_update; }
Instead of filenames the script actually uses I've just given it a couple of counts for the inner loop. In place of the actual processing done on the file contents I've included a sleep.

I'm doing something wrong because the progress bar advances one step and that's it until it completes. To be honest the example code given in the module docs is a little hard for me to follow. I don't understand what is setting $_ so maybe I'm not doing something with that that I shouldbe doing.

Can anyone say what I'm doing wrong?

Replies are listed 'Best First'.
Re: Term::ProgressBar won't update
by hv (Prior) on Sep 17, 2022 at 20:05 UTC

    In the docs example, it is implicitly looping over $_ in the line for (0 .. $max). In your case you are using $i (which is probably a good thing), so you should use that instead: $next_update = $progress->update($i) if $i >= $next_update.

      Yes that did it. I still don't for the life of me see where $_ is getting updated in the sample code. Isn't $i the index in the sample? Maybe it's some Perl voodoo/arcana I don't understand.
        I ... don't ... see where $_ is getting updated in the sample code.

        In a Perl-style for-loop like
            for (0 .. $max) { ... }
        the scalar variable $_ is the implicit loop or "topicalized" variable. (Update: See Foreach Loops in perlsyn.)


        Give a man a fish:  <%-{-{-{-<

Re: Term::ProgressBar won't update
by kcott (Archbishop) on Sep 18, 2022 at 01:00 UTC

    G'day cormanaz,

    "I don't understand what is setting $_ ..."

    In the examples in the "module docs", $_ is being set in the outer loop and $i is being set in the inner loop. A quick demonstration:

    $ perl -E ' for ("a" .. "b") { for my $i (1 .. 2) { say "\$_[$_] \$i[$i]"; } } ' $_[a] $i[1] $_[a] $i[2] $_[b] $i[1] $_[b] $i[2]

    Using a named variable, as you've done, is much safer. $_ is a global variable: it could be changed by something in "stuff my script is actually processing"; or, some later addition to your code could affect it.

    $ perl -E ' for my $f ("a" .. "b") { for my $i (1 .. 2) { say "\$_[$_] \$f[$f] \$i[$i]"; } } ' $_[] $f[a] $i[1] $_[] $f[a] $i[2] $_[] $f[b] $i[1] $_[] $f[b] $i[2]

    Here's a highly contrived example of additional code changing $_:

    $ perl -E ' for my $f ("a" .. "b") { for my $i (1 .. 2) { say "\$_[$_] \$f[$f] \$i[$i]"; } s/$/.bu/; } ' $_[] $f[a] $i[1] $_[] $f[a] $i[2] $_[.bu] $f[b] $i[1] $_[.bu] $f[b] $i[2]

    If you'd put "use warnings;" near the top of your code, you would have seen a series of "Use of uninitialized value $_ ..." warnings. This may have alerted you to the problem you describe.

    While I appreciate that the code you provided was purely for demo purposes, I thought I'd point out that "my $max = $f;" is going to be a problem with real filenames (you may already be aware of this). You get no output from:

    $ perl -E ' for my $f ("a" .. "b") { my $max = $f; for my $i (1 .. $max) { say "\$f[$f] \$i[$i]"; } } '

    Again, the warnings pragma points to the problem:

    $ perl -E ' use warnings; for my $f ("a" .. "b") { my $max = $f; for my $i (1 .. $max) { say "\$f[$f] \$i[$i]"; } } ' Argument "a" isn't numeric in foreach loop entry at -e line 7. Argument "b" isn't numeric in foreach loop entry at -e line 7.

    I strongly recommend that you include the warnings pragma in all of your code. It's lexically scoped: turn off selected warnings, in a limited scope, for special cases.

    $ perl -E ' use warnings; my @rgb = qw{#ff0000 #00ff00 #0000ff}; ' Possible attempt to put comments in qw() list at -e line 4. $ perl -E ' use warnings; my @rgb; { no warnings "qw"; @rgb = qw{#ff0000 #00ff00 #0000ff}; } '

    — Ken