Reputation: 12288
The thing I want to know here should be really 'basic', but it is a question in my mind for long time and no idea where the trick is.
Let's say in a time-consuming program(either bash
or Python
), I have to print out the percentage of the progress when it's running, and basically I want to print 1%
, and after a certain time, I print 2%
, etc.. I want '2%'
to be displayed exactly at the same position where '1%'
was displayed, rather than they're like "1% 2%" or whatever. You know wget
, what I want is exactly what wget does, to show the progress of the downloading progress. Do I need to clear the previously printed character, but how?
How does it work basically...
Thanks,
Upvotes: 3
Views: 2667
Reputation: 9539
In Python 3.6+, Deitrich's answer can be shortened to
import time
for i in range(101):
print(f'\r{i}%', end='')
time.sleep(0.01)
The carriage return takes you back to the beginning of the line, and passing in an empty string as the end parameter stops you from moving to the next line.
I also find this generator useful when I don't know how long an action will take. It will print out the three dots loading animation. Works in Python 3.3+
def loading_dots():
while True:
yield("\r. ")
yield("\r.. ")
yield("\r...")
You would use it like this
max_attempts = 100
dots = loading_dots()
for i in range(max_attempts):
if is_finished(): # you would have to create this function
break
time.sleep(2)
print(next(dots), end="", flush=True)
else:
raise Exception("timed out")
And if you ever want to clear the current line, you can do so like this (Python 3.3+)
print('\r' + ' '*80 + '\r', end='')
Upvotes: 1
Reputation: 195
this is a simple timer perhaps help you ;-) write another character to overwrite the current position with print function.
from __future__ import print_function
def timer():
for h in range(0, 24):
for m in range(0, 60):
for s in range(0, 60):
time.sleep(1)
print ("Elapsed time : %s:%s:%s" % (h, m, s), end="\r")
Upvotes: 1
Reputation: 44394
A Python solution has been offered, it is not particularly difficult (or different) in bash:
i=20
while (( i-- ))
do
echo -ne "\r$i% done "
sleep 1
done
echo
The flush
is not required in bash because that's invoked by echo
anyway. The arguments to echo
, -n
supresses a new-line, and -e
translates the \r
notation. Note the hack with a couple of spaces at the end of the text in the string, to clear to end-of-line.
Upvotes: 1
Reputation: 213578
I'm going to answer in Python, since it's easier.
You can print a backspace to the terminal to move the cursor to the left, and then write another character to overwrite the current position. You can also use a carriage return to go to the beginning of the line.
import time
import sys
for x in range(101):
sys.stdout.write('\r%d%%' % x)
sys.stdout.flush()
time.sleep(0.2)
sys.stdout.write('\n')
Using a carriage return and rewriting the whole line is the easiest, since you don't have to be careful about how many backspaces to print.
Note that if the new line is shorter than the old line, the old line will still show through.
import sys
sys.stdout.write('this is a very long line')
sys.stdout.write('\rshort line')
sys.stdout.write('\n')
Output:
short linevery long line
A typical solution is to write spaces over the long line.
Upvotes: 6