How do I write output in same place on the console?
Asked Answered
F

9

203

I am new to python and am writing some scripts to automate downloading files from FTP servers, etc. I want to show the progress of the download, but I want it to stay in the same position, such as:

output:

Downloading File FooFile.txt [47%]

I'm trying to avoid something like this:

     Downloading File FooFile.txt [47%]
     Downloading File FooFile.txt [48%]
     Downloading File FooFile.txt [49%]

How should I go about doing this?


Duplicate: How can I print over the current line in a command line application?

Factor answered 5/2, 2009 at 18:11 Comment(2)
you might be interested in this easy-to-use module, it's a text progress bar. pypi.python.org/pypi/progressbar/2.2Ceja
Does this answer your question? Print in one line dynamicallyIntercourse
C
295

You can also use the carriage return:

sys.stdout.write("Download progress: %d%%   \r" % (progress) )
sys.stdout.flush()
Catanddog answered 5/2, 2009 at 18:22 Comment(7)
Very common and simple solution. Note: if your line is longer than the width of your terminal, this gets ugly.Nobe
I also had to add a call to sys.stdout.flush() so the cursor didn't bounce aroundFactor
Is it possible to do this with multiple lines? Lets say I have three different downloads, and I want to show the progress of each one on its own line.Lavena
I like to put the \r at the beginning of the line, and add a \x1b[K to clear the previous text.System
What if I have multiple lines? For example, multiple downloads happening at the same time. It doesn't seem to work when I just add newlines, it prints infinitely. I.e., sys.stdout.write("Download progress: %d%% \n\r" % (progress) ) doesnt workMcclenaghan
It seems like the simplest solution for python 3 (as mentioned in answers below) is: print("sample text", end='\r", flush=True)Monophony
@Monophony that worked seamlessly. Just fix the quotes with \r :)Roche
O
64

Python 2

I like the following:

print 'Downloading File FooFile.txt [%d%%]\r'%i,

Demo:

import time

for i in range(100):
    time.sleep(0.1)
    print 'Downloading File FooFile.txt [%d%%]\r'%i,

Python 3

print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

Demo:

import time

for i in range(100):
    time.sleep(0.1)
    print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

PyCharm Debugger Console with Python 3

# On PyCharm Debugger console, \r needs to come before the text.
# Otherwise, the text may not appear at all, or appear inconsistently.
# tested on PyCharm 2019.3, Python 3.6

import time

print('Start.')
for i in range(100):
    time.sleep(0.02)
    print('\rDownloading File FooFile.txt [%d%%]'%i, end="")
print('\nDone.')
Otolaryngology answered 5/2, 2009 at 19:29 Comment(5)
use this for python 3+: print('Downloading File FooFile.txt [%d%%]\r'%i, end="")Allergy
On PyCharm Debugger console, \r needs to come before the text. Otherwise, the text may not appear at all, or appear inconsistently. I added the version that works for me as an edit, because I couldn't write multi-line code in this answer. I put it on my gist so people can view it while the edit is awaiting approval: gist.github.com/yulkang/40168c7729a7a7b96d0116d8b1bc26dfMesocarp
"\r" at the end of the string works for me in the debugger console on PyCharm 2020.1 (PyCharm 2020.1.2 (Community Edition); Build #PC-201.7846.77, built on May 31, 2020).Torment
What about 2 lines print ?Steffin
minor detail it's possible to move the \r to the end parameter, like: print('Downloading File FooFile.txt [%d%%]'%i, end='\r')Moraine
P
29

Use a terminal-handling library like the curses module:

The curses module provides an interface to the curses library, the de-facto standard for portable advanced terminal handling.

Palstave answered 5/2, 2009 at 18:19 Comment(2)
Not available for Windows.Cappella
@Diego there's now a support library for curses module on Windows. see https://mcmap.net/q/129423/-curses-alternative-for-windows-closedLinlithgow
C
16

Print the backspace character \b several times, and then overwrite the old number with the new number.

Cinchonine answered 5/2, 2009 at 18:14 Comment(3)
interesting, I hadn't thought of doing it that way.Offshoot
I like this because it doesn't clear previous commands (if you have multiple stages you want to leave on the screen)Concernment
Using carriage return (e.g. print 'Downloading.... \r') also doesn't clear previous data, but it prevents having to know how far back to back up.Lurleen
E
16

For Python 3xx:

import time
for i in range(10):
    time.sleep(0.2) 
    print ("\r Loading... {}".format(i)+str(i), end="")
Excommunicate answered 24/8, 2017 at 23:28 Comment(0)
D
9
#kinda like the one above but better :P

from __future__ import print_function
from time import sleep

for i in range(101):
  str1="Downloading File FooFile.txt [{}%]".format(i)
  back="\b"*len(str1)
  print(str1, end="")
  sleep(0.1)
  print(back, end="")
Dulcet answered 2/11, 2011 at 4:14 Comment(1)
Why is this better than the above (I'm a Python n00b, so please excuse my ignorance :-))?Attila
M
4

A neat solution that has been working for me is:

from __future__ import print_function
import sys
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is {}% complete      ".format(perc), end='\r')
    sys.stdout.flush()
print("")

The sys.stdout.flush is important otherwise it gets really clunky and the print("") on for loop exit is also important.

UPDATE: As mentioned in the comments, print also has a flush argument. So the following will also work:

from __future__ import print_function
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is {}% complete      ".format(perc), end='\r', flush=True)
print("")
Micropaleontology answered 10/5, 2017 at 6:32 Comment(1)
In modern Python, you can supply an arg of flush=True to print, so there's no need for the extra sys.stdout.flush() call.Rema
T
1

In python 3 the function print can get many arguments. the full signature of the function print is: print(args*, sep=' ', end='\n', file=sys.stdout, flush=False)

when sep is the separator of the arguments from args*, end is how to end the printed line ('\n\ means a new line) file is to where print the output (stdout is the consul) and flush is if to clean the buffer.

Usage Example

import sys

a = 'A'
b = 0
c = [1, 2, 3]

print(a, b, c, 4, sep=' * ', end='\n' + ('-' * 21), file=sys.stdout, flush=True)

Output

A * 0 * [1, 2, 3] * 4
---------------------

In python there are many ways to format string and even a built in formatted string type.

How to format string

  1. the format() function. (some examples)
  2. Formatted String Literals or in the common name f-strings.
  3. format using % (more about this)

Examples

name = 'my_name'

>>> print('my name is: {}'.format(name))
my name is: my_name

# or
>>> print('my name is: {user_name}'.format(user_name=name))
my name is: my_name

# or
>>> print('my name is: {0}'.format(name))
my name is: my_name

# or using f-strings
>>> print(f'my name is: {name}')
my name is: my_name

# or formatting with %
>>> print('my name is: %s' % name)
my name is: my_name
Thereafter answered 2/5, 2021 at 9:59 Comment(1)
First example has "sys.sdtout" gives a syntax error. Change to "sys.stdout".Teledu
P
0
x="A Sting {}"
   for i in range(0,1000000):
y=list(x.format(i))
print(x.format(i),end="")

for j in range(0,len(y)):
    print("\b",end="")
Prem answered 3/3, 2018 at 17:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.