views:

227

answers:

4

Okay, so what I'm trying to do is print out a percentage complete to my command line, now, I would like this to simply 'update' the number shown on the screen. So somehow go back to the beginning of the line and change it.

For example the windows relog.exe command-line utility (which can convert a .blg file to a .csv file) does this. If you run it, it will display a percentage complete.

Now this is probably written in C++. I don't know if this is possible in perl as well ?

A: 

In C and C++, the trick is to print char #13. Maybe it can work in Perl.

for (int pc = 0 ; pc <= 100 ; ++pc)
    printf("Percentage: %02d %%  %c", pc, 13);
printf("\n");
Didier Trosset
Downvote for untested code.
daxim
+7  A: 

Use "\r" or "\015" octal (aka "Return caret" aka "Carriage Return" character originating from typewriter days :)

> perl5.8 -e 'print "11111\r222\r3\n";'
32211
> perl5.8 -e 'print "11111\015222\0153\n";'  
32211

Just don't forget to print at least as many characters as the longest string already printed to overwrite any old characters (as you can see in example above, the failure to do so will keep old characters).

Another thing to be aware of is, as Michael pointed in the commment, the autoflush needs to be turned on while these printings happen, so that the output doesn't wait for newline character at the very end of the processing.

UPDATE: Please note that 013 octal character recommended in another answer is actually a Vertical Tab:

> perl5.8 -e 'print "11111\013222\0133\n";'    
11111
     222
        3
DVK
For a full list of special characters you can print, see http://en.wikipedia.org/wiki/ASCII
DVK
You also need to turn on autoflushing (`$| = 1`) as by default output is buffered until a newline is seen. (Or until the buffer is full, but that won't happen for a progress meter.)
Michael Carman
@Michael - my original answer included autoflushing, I removed it to keep the line lengths down as it was not strictly speaking related to the meat of the question... Adding as a note
DVK
@DVK FWIW that other answer didn't suggest octal 13, it suggested *decimal* 13, which is in fact `\r` (`\x0d`).
hobbs
And also note that the vertical tab isn't something that's recognized in every shell. :)
Robert P
Thanks man, that was what I was looking for, and indeed, also needed autoflushing !
Pmarcoen
@DVK: I feel frustrated to get a -1 when you cannot figure there's no difference between 015 (octal) and 13 (decimal).
Didier Trosset
@Didier - +1-ed you to assuage your frustration... though to be hoinest your answer didn't really deserve a +1 independent of whether I personally read it carefully enough or not. No explanation of why 13, no attempt to test if it works.
DVK
+6  A: 

Depending on what you'd like to do, pv might solve your problem. It can wrap any script that takes a file as input, and add a progress bar.

For example

pv data.gz | gunzip -c | ./complicated-perl-script-that-reads-stdin

pv is packaged for RedHat/CentOS and Ubuntu at least. More information: http://www.ivarch.com/programs/pv.shtml

Otherwise I'd use CPAN, e.g. Term::ProgressBar.

rjh
+1 for Progress::Bar, the best solution for the job.
Ether
@rjh - I have a feeling he is on Windows, so he may need a DOS/Windows pv port
DVK
+1 for CPAN module - I'm not sure how usedful it's to OP but it's very educational to know about
DVK
+1  A: 

You can also use \b to move back one character:

local $| = 1; #flush immediately
print "Doing it - 10%";
sleep(1);
print "\b\b\b";
print "20%";
print "\n", "Done", "\n";
deepakg