How can I edit a string that was printed to stdout? - python

How can I edit a string that I just printed? For example, for a countdown counter (First prints 30, then changes it to 29 and so on)
Thanks.

Print a carriage return \r and it will take the cursor back to the beginning on the line. Ensure you don't print a newline \n at the end, because you can't backtrack lines. This means you have have to do something like:
import time
import sys
sys.stdout.write('29 seconds remaining')
time.sleep(1)
sys.stdout.write('\r28 seconds remaining')
(As opposed to using print, which does add a newline to the end of what it writes to stdout.)

If you're targeting Unix/Linux then "curses" makes writing console programs really easy. It handles color, cursor positioning etc. Check out the python wrapper:
http://docs.python.org/library/curses.html

If you're on a xterm-like output device, the way you do this is by OVERWRITING the output. You have to ensure that when you write the number you end with a carriage-return (without a newline), which moves the cursor back to the start of the line without advancing to the next line. The next output you write will replace the current displayed number.

You can not change what you printed. What's printed is printed. But, like bradley.ayers said you can return to the beginning of the line and print something new over the old value.

You can use the readline module, which can also provide customized completion and command history.

Related

How can I edit what has already been printed?

For example, let's say one of the printed things is "Hello World" and the second is "Hello". How would I print "Hello" on the same line as the one that says "Hello World"? This is just an example. Realistically I have no idea how long the printed text will be.
Here is an example script:
x = open("file.txt", "r+").read().split("\n")
for i in x:
print(something)
where something = I don't know. I want the output to be what the first line of the text file says, then what the second line says, and so on except print the second/third/fourth... line over the first line and each line is an unknown length, some shorter than others. Lets say the file.txt says:
Overflow
Stack
I would want it to print "Overflow" then "Stack", except each word gets printed on the first line and once you print "Stack", every part of "Overflow" can't be seen
Keep in mind that print("Hello World", end="\r") won't work because of the length.
You could work around the \r solution by padding each line with spaces according to the previous line:
prev_size = 0
with open("file.txt", "r+") as f:
for line in f:
print(f"{line.strip()}{' '*prev_size}", end='\r')
prev_size = len(line)
You would probably want to add a sleep between prints to be able to actually see the text changing...
When you use the print function in python, you're just pushing characters onto a pipe somewhere (the pipe might be connected to the standard out, but your program doesn't know that). Once its, pushed, there is nothing you can do to un-push it. Afterall, the pipe might not even be connected to a screen. It might be directly connected to the input of another program, or it might be using a physical printer for display. What would un-pushing even mean in those cases?
There are, however, special control characters (such as the "backspace" character) that you push to the pipe to signal that you want to erase characters. However, The terminal you are connected to is free to do what it wants with these characters. It can respect your wishes and erase characters, or it can print the literal '\b' characters to indicate a backspace, or it can completely ignore you and continue to print after the previous letters. That's completely out of your control.
Assuming the terminal that print the characters supports overwriting the characters, you can use the ANSI control sequences. The sequence for moving cursor to beginning of line is '\033[1G' and for erasing the everything from current cursor position to end of line is '\033[0K'. So,
import time
print('hello world', end='', flush=True) # prints "hello world" with no newline at the end
time.sleep(2) # wait 2 seconds
print('\033[1G\033[0K', end='') # moves cursor to beginning of line and erases the line
print('hi') # prints "hi" with newline at the end
flush=True is needed because the print function is buffered by default and doesn't actually print anything until it hits a newline. This tells the function you want to flush the buffer immediately.
Take a look at ANSI escape codes, section on "CSI sequences" to see what other codes are available.

carriage return not working in Terminator but works fine in Terminal in Ubuntu

I am using '\r' in print function in python 2.7. It works fine in terminal but not in terminator.
For example:
I am using a decrement counter which decrements from n to 0. In the Terminal, the count values are updated at the same line while in terminator, it count values get printed on new line. I am using terminator for various reasons such as its advanced features like tab partitioning etc. Below is the code snapshot
import sys
import time
if __name__ == "__main__":
sleep_time_in_sec = 15
time_to_go_back_mns = 10
for remaining in range(sleep_time_in_sec, -1, -1):
sys.stdout.write("\r")
sys.stdout.write(
"{:2d} seconds remaining to read last {:2d} minutes of data and perform prediction .....".format(remaining,
time_to_go_back_mns))
sys.stdout.flush()
time.sleep(1)
Can someone please suggest a fix
Simply place the \r at the end of your write statement like so:
sys.stdout.write(
"{:2d} seconds remaining to read last {:2d} minutes of data and perform prediction .....\r".format(remaining,
time_to_go_back_mns))
New data will then overwrite the line, you can use flush() to clear the line before writing to it again:
sys.stdout.flush()
Make sure that on the terminator side of things your profile settings are clean. Be sure to check out the compatibility tab as it mentions weird application behaviour.
note that carriage return stops functioning if the terminal size is too small. It will only return to the first character of the LAST line
Original answer
\r actually means "carriage return" whereas \n is a line feed.
In Linux (Unix) you'd usually use either a \n or \r\n.
So if your goal is to go to a new line you should use \n instead.
The reason it might work in the "terminal" (whichever one that might be) is because some terminals (notably gnome's terminal) catches the \r and treats it as a \r\n.
The answer for this post goes to #Rick van Lieshout.
In my case, I was using multiple tabs in the same window as a result of which \r was not working. It worked fine when I used it in a separate window or a tab with full horizontal width.

Unprint a line on the console in Python?

Is it possible to manipulate lines of text that have already been printed to the console?
For example,
import time
for k in range(1,100):
print(str(k)+"/"+"100")
time.sleep(0.03)
#>> Clear the most recent line printed to the console
print("ready or not here I come!")
I've seen some things for using custom DOS consoles under Windows, but I would really like something that works on the command_line like does print without any additional canvases.
Does this exist? If it doesn’t, why not?
P.S.: I was trying to use curses, and it was causing problems with my command line behaviour outside of Python. (After erroring out of a Python script with curses in it, my Bash shell stopped printing newline -unacceptable- ).
What you're looking for is:
print("{}/100".format(k), "\r", end="")
\r is carriage return, which returns the cursor to the beginning of the line. In effect, whatever is printed will overwrite the previous printed text. end="" is to prevent \n after printing (to stay on the same line).
A simpler form as suggested by sonrad10 in the comments:
print("{}/100".format(k), end="\r")
Here, we're simply replacing the end character with \r instead of \n.
In Python 2, the same can be achieved with:
print "{}/100".format(k), "\r",
What you need are ANSI Command Codes.
http://en.wikipedia.org/wiki/ANSI_escape_code#CSI_codes
You also need code to activate ANSI Command Codes. I would use Colorama.
https://pypi.python.org/pypi/colorama
OR
Use curses (Python 3.4+) module.
The simplest method (at least for Python 2.7) is to use the syntax:
print 'message', '\r',
print 'this new message now covers the previous'
Notice the extra ',' at the end of the first print. This makes print stay on the same line. Meanwhile, the '\r' puts the print at the beginning of that line. So the second print statement overwrites the first.

Clearing old data from sys.stdout in Python

There's something I don't get when writing to sys.stdout in Python.What I want is to write some strings into stdout without preprending the stuff which already has been written before that.
So doing this:
while True:
sys.stdout.write("k")
sys.stdout.flush()
sys.stdout.write("d")
After some "k" data has been written into stdout in a loop I need to write some new data afterwards,which is "d" for the sake of example.
I am getting : "k d" in the output."K" from the loop writes is still in stdout.
What I want to get is just "d" .
Why?
How can I clear the stdout before writing new data into it?
Btw,using print() instead still accumulates the old data into final output.
Using python 2.7 on Linux
Terminals don't work that way. flush just flushes the buffer (i.e. characters that may not have been printed to screen yet), it does not clear the screen.
If you want to erase one character, you need to print a literal backspace control character, and then print something over your previous output (like a space):
sys.stdout.write("\b ")
However. Your asking this belies a deep misunderstanding of how terminals work. Think of it like a text processor - there is text on the screen, and a cursor (which is invisible). You need to tell the cursor what to do to manipulate the text on the screen. Since the cursor is always in overwrite mode, a trick that is often useful is to go back to the start of the line:
sys.stdout.write("\r")
and overwrite your data on that line. Note that if your new data is of lesser length than your previous data, this will leave some amount of previous data on the screen.
There are other tricks you can use if neither of these fits your bill, like outputting terminal control sequences to stdout.
(also, unless you have a specific need for using sys.stdout, just use print.)
I do have to print "k" but one line before "d".I want to print "d" in a completely new line.
Simply write a newline between the two:
sys.stdout.write("\n")
Or just use print, which adds an implicit newline at the end:
print "k"
print "d"

Python print statement prints nothing with a carriage return

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?
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.
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
If your terminal is line-buffered, you may need a sys.stdout.flush() to see your printing if you don't issue a linefeed.

Categories