2

I am trying to overwrite a print statement in a foreach loop to create somewhat of a progress bar.

What I am doing:

my $arraySize = @listOfIps;
local $| = 1;   
my $counter = 0;
my $progressString;

print 'Progress: ';

foreach my $ip (@listOfIps) {

        $counter++;
        print "\b" x length($progressString) if defined $progressString;
        $progressString = "\r$counter / $arraySize - Working on $ip"; 
        print $progressString; 

        #does stuff here but thats irrelevant to the problem

}

The problem I am having is that when the foreach loop gets to an IP that is shorter than the previous one it has printed eg 10.0.0.1 it still displays the extra characters left over from the previous longer print statement.

The problem:

Progress: 3 / 10 - Working on 200.144.223.211

then overwriting this print statement with the next smaller ip address in the array gives:

Progress: 4 / 10 - Working on 10.0.0.1223.211

and so on... when actually it should print just :

Progress: 4 / 10 - Working on 10.0.0.1

so that it does not have any of the characters from the previous print left over.

There must be something really obvious I am overlooking here, as I can't see any reason why this would not be working.

halfer
  • 19,824
  • 17
  • 99
  • 186
yonetpkbji
  • 1,019
  • 2
  • 21
  • 35

1 Answers1

3

Use printf with a format that pads the IP string with spaces:

printf "\r$counter / $arraySize - Working on %-15s", $ip;

Adapt the number 15 to the length of your longest IP. If you have a variable, you can use it in the format string like so (thanks amon for sharing):

printf ".... Working on %-*s", $length, $ip;

Though that is quite excessive, since you can control all variable length strings with the printf:

printf "\r%-*s / %-*s - Working on %-*s", 5, $counter, 5, $arraySize, 15, $ip;

The \b escape is apparently a non-destructive backspace, which does not delete, according to this answer. Which would mean that it does just about the same as \r in your case.

Community
  • 1
  • 1
TLP
  • 66,756
  • 10
  • 92
  • 149
  • Ah I see, I thought it was a backspace but didn't realise it did not remove what was previously there (non-destructive) useful link thanks. – yonetpkbji Dec 04 '13 at 12:14
  • @perl-user You're welcome. It was the top search result for the google query `\b character`. – TLP Dec 04 '13 at 12:15
  • You've already got a solution to calculate the length of the string, and you know about `\r`. What more do you need to know? – TLP Dec 04 '13 at 12:29
  • Your right, what I really meant was how do I transplant the value from the length of the string into the `printf` in place of the `%-15s`, thanks – yonetpkbji Dec 04 '13 at 12:52
  • @perl-user Just insert the variable, using support curly brackets: `%-${length}s` (for variable `$length`) – TLP Dec 04 '13 at 12:55
  • Excellent, thats what I required. Thanks a lot – yonetpkbji Dec 04 '13 at 13:07
  • 2
    there is no need to interpolate field widths into a pattern – use a `*` instead: `printf "%*s\n", 5, "foo"` would have two leading spaces. – amon Dec 04 '13 at 13:07
  • @amon That's a nice feature, and curiously hidden in the documentation (perldoc -f sprintf). Thanks. – TLP Dec 04 '13 at 13:14