8

In Python you can print on the same line using \r to move back to the start of the line.

This works well for progress bars or increasing precentage counters, eg: Python print on same line

However when printing lines that may decrease in length, this leaves the previous lines text there, eg:

import sys
for t in ['long line', '%']:
    sys.stdout.write(t + '\r')
sys.stdout.write('\n')

Leaves the terminal text as: %ong line.

Whats the best way to write a shorter line after a longer one, when printing to the same line?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 1
    Note that some of the answers to https://stackoverflow.com/questions/3249524 (lower down on the page), cover this question, but the question is in fact different. – ideasman42 Jul 23 '17 at 09:39
  • Does this answer your question? [How to overwrite the previous print to stdout?](https://stackoverflow.com/questions/5419389/how-to-overwrite-the-previous-print-to-stdout) – Karl Knechtel Jan 02 '23 at 00:16
  • @karl-knechtel that question doesn't ask about the problem of trailing text being left when using `\r`. – ideasman42 Jan 03 '23 at 00:44
  • It doesn't ask explicitly, perhaps because it didn't occur to OP as a problem; but it's a common inference, and is addressed by the top answer there. – Karl Knechtel Jan 03 '23 at 00:47

3 Answers3

10

Along with \r, the ansi-sequence \033[K is needed - erase to end of line.

This code works as expected.

import sys
for t in ['long line', '%']:
    sys.stdout.write('\033[K' + t + '\r')
sys.stdout.write('\n')

Note, this doesn't work when the string includes tabs, you may want to replace:

sys.stdout.write('\033[K' + t + '\r') with ...

sys.stdout.write('\033[K' + t.expandtabs(2) + '\r')

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 1
    I found that the erase sequence interferes with space-expanded tabs unless you put it in a separate string like `print('\033[K' + '\tWords here'.expandtabs(2))` – Addison Klinke Dec 07 '20 at 19:51
  • Thanks for pointing this out, added note, I'm not sure if there is a better way to solve this than what you've suggested. – ideasman42 Dec 07 '20 at 22:28
  • Can you explain why you added the `\r` to the end of the string? I tried it with `print('\r\033[K'+t)` and it seems to work. – Manngo Apr 05 '22 at 23:56
  • It can be at the beginning of the line too, the cursor will then be left at the end. – ideasman42 Apr 06 '22 at 02:17
2

If you have been printing without a newline character at the end of your print, you can flush your latest print with:

print('\r\033[K', end='')

If you previously printed with a new line, you can use the ANSI escape code to move up one line and to the beginning of the line with:

print('\033[F', end='')

You can then flush the line as before.

An example usage:

LINE_FLUSH = '\r\033[K'
UP_FRONT_LINE = '\033[F'
...
print(UP_FRONT_LINE + LINE_FLUSH + msg)
ljden
  • 352
  • 1
  • 11
1

I think the simplest way to do this is to write spaces over the characters. For this, it'd be a good idea to write as many spaces are needed to cover the last line only. Example:

previousLength = 0
for t in ["long line", "%"]:
    print(" " * previousLength, end="\r") 
    print(t, end="\r")

    previousLength = len(t)

print("\n")
M Palmer
  • 181
  • 4