views:

314

answers:

3

I'm trying to write a simple tool that reads files from disc, does some image processing, and returns the result of the algorithm. Since the program can sometimes take awhile, I like to have a progress bar so I know where it is in the program. And since I don't like to clutter up my command line and I'm on a Unix platform, I wanted to use the '\r' character to print the progress bar on only one line.

But when I have this code here, it prints nothing.


# Files is a list with the filenames
for i, f in enumerate(files):
    print '\r%d / %d' % (i, len(files)),
    # Code that takes a long time

I have also tried:


print '\r', i, '/', len(files),

Now just to make sure this worked in python, I tried this:


heartbeat = 1
while True:
    print '\rHello, world', heartbeat,
    heartbeat += 1

This code works perfectly. What's going on? My understanding of carriage returns on Linux was that it would just move the line feed character to the beginning and then I could overwrite old text that was written previously, as long as I don't print a newline anywhere. This doesn't seem to be happening though.

Also, is there a better way to display a progress bar in a command line than what I'm current trying to do?

+1  A: 

Handling of carriage returns in Linux differs greatly between terminal-emulators.

Normally, one would use terminal escape codes that would tell the terminal emulator to move the virtual "carriage" around the screen (think full-screen programs running over BBS lines). The ones I'm aware of are the VT100 escape codes:

\e[A: up
\e[B: down
\e[C: right
\e[D: left
\e[1~: home
\e[4~: end

Where \e is the escape character, \x1b.

Try replacing all \r's with \e[1~

Also see this post

amphetamachine
Why would his second example work, then?
danben
+3  A: 

Try adding sys.stdout.flush() after the print statement. It's possible that print isn't flushing the output until it writes a newline, which doesn't happen here.

interjay
Yep, that did it. Still not entirely sure why the hello world example worked. It didn't issue a line feed either. Maybe because the print statement was running enough that it auto-flushed the buffer after a certain number of characters?
Jonathan Sternberg
Yes, it must have flushed the buffer when it became full.
interjay
Alternatively, one may use `sys.stderr` to print immediately to the screen. By default `stderr` is unbuffered.
amphetamachine
+2  A: 

If your terminal is line-buffered, you may need a sys.stdout.flush() to see your printing if you don't issue a linefeed.

Mark Tolonen