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

I'm looking for a reason why this happens when I print a \r carriage return without a new line...Here's a sample of my code:
open(LOG, "+>Test.log"); for($x=0;$x<=100;$x++){ print "\rProgress...$x\%"; print LOG "\rProgress...$x\%"; } print "\rProgress...Done!\n"; print LOG "\rProgress...Done!\n"; close LOG; $wait=<>;
When executed, the STDOUT (command window) says:
"Progress...Done!"
but my log file says:
"Progress...0% Progress...1% Progress...2% ... Progress...100% Progress...Done!"
Is there a way I can force the log file to behave like the STDOUT in the command window, and overwrite the previous 'progress'?

Replies are listed 'Best First'.
Re: overwrite last line printed
by SuicideJunkie (Vicar) on Nov 25, 2011 at 20:29 UTC

    Text editors are smart enough to show you all the contents of the file, even if your line endings are mac style.

    If you want the file to not contain those status updates, you can seek backwards in the file and overwrite, or better yet, simply don't print those progress lines to the file in the first place.

    I suggest printing the "Progress..." messages to STDERR, while the useful stuff goes to STDOUT and/or the file.

Re: overwrite last line printed
by TJPride (Pilgrim) on Nov 25, 2011 at 21:15 UTC
    Just set up a function that prints to both screen and to the log file. Use that function when you want it to be logged; use regular print if it's the progress messages.

    sub dPrint { my ($text, $handle) = @_; print $text; print $handle $text; }

    Alternately, just do ....... until it finishes. Maybe one . per 5% or a certain number of records or whatever?

Re: overwrite last line printed
by NetWallah (Canon) on Nov 25, 2011 at 23:39 UTC
    You are suffering from buffering.

    Try adding "$|=1" at the start of your code.

                "XML is like violence: if it doesn't solve your problem, use more."

      I don't see what buffering has to do with this problem. As mentioned above by SuicideJunkie if you want to overwrite the last line of a file you need to use seek.

        Well , in the code posted, without $|=1 the user won't see any progress message until DONE

        perl -e " $|=0; for (1,2,3) { print qq[\r hi n $_] ; sleep 1; } print +qq[\r done now \n]; " perl -e " $|=1; for (1,2,3) { print qq[\r hi n $_] ; sleep 1; } print +qq[\r done now \n]; "

        On the other hand, buffering is probably irrelevant if you seek , whether seek flushes the buffers (what probably happens) or discards them

Re: overwrite last line printed
by Anonymous Monk on Nov 26, 2011 at 14:33 UTC

    Try logging progress to both default output (STDOUT) and global filehandle LOG with LOGress :)

    BEGIN { my $started = !!0; sub LOGress { my $string = join '', @_; my $before = tell select; print $string; my $after = tell select; if( $started ){ seek LOG -abs( $after - $before ), 2; # rewind } print LOG $string; if( 0 <= index $string, "\n" ){ $started = !!0; } else { $started = !!1; } } } ... LOGress "\rProgress...$x\%"; ... LOGress "\rProgress...Done!\n"; # \n signals end

    use autodie qw/ open close seek tell /; to die if those calls fail