How overwrite many print lines in the while loop - python

I want to ovewrite 2 separate print lines in while True loop. I tried \r and \n but it is not working. When using \r \n override only 1 line or 2 line prints continously.how i fix this?
import sys
import time
tot = 5
new = 2
while True:
sys.stdout.write('{0}\n\r'.format(tot))
sys.stdout.write('{0}\n\r'.format(new))
sys.stdout.flush()
time.sleep(1)
tot += 1
new += 1

\r brings you to the beginning of the line where you will start overwriting stuff.
\n adds a newline
\n\r takes you to the next line, and then bring you to the beginning of that line, which is already a blank new line, and so the \r isn't actually doing anything and this is the same as just doing \n.
If you only wish to overwrite a single line you can do this with \r followed by your text. Make sure that whatever you print out has enough spaces at the end of it to make it the same length as the line you are overwriting, otherwise, you'll end up with part of the line not getting overwritten.
But since you've clarified that you need to overwrite multiple lines, things are a little bit trickier. Carriage returns (\r) were originally created to help with problems early printers had (This Wikipedia article explains these problems). There is a completely different mechanism for overwriting multiple lines that isn't exposed natively by Python, but this Stack Overflow question lists a few 3rd party libraries you can install that will help you accomplish this.

To overwrite the previous line, you need to have not yet output a newline. So I don't think you can overwrite multiple lines, sadly. To do one though, try something like this:
while some_condition:
sys.stdout.write("\r{0}".format("your text here"))
sys.stdout.flush()
The \r here (called a "carriage return") moves the printing cursor back to the beginning of the line (ie, to right after the most recent newline \n). You cannot go back farther than that, though.

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.

How to exclude \n and \r from tell() count in Python 2.7

I want to keep track of the file pointer on a simple text file (just a few lines), after having used readline() on it. I observed that the tell() function also counts the line endings.
My questions:
How to instruct the code to skip counting the line endings ?
How to do the first question regardless the line ending type (to work the same in case the text file uses just \n, or just \r, or both) ?
You are navigating into trouble.
DOn't do that: either use the number "tell" tells you about, or count what you have in memory, regardless of the file contents.
You won't be able to correlate a position in text, read in memory, to a physicall place in a text file: text files are not meant for that. They are meant to be read one line at a time, or in whole: your pogram consumes the text, and let the OS worry about the file position.
You can open your file in binary mode, read its contents as they are into memory, and have some method of retrieving readable text from those contents as needed - doing this with a proper class can make it not that messy.
Consider the problem you already have with the line-endings which could be either "\n" or "\r\n" and still count as a single character, and now, imagine that situation one hundred fold more complex if the file has a single utf-8 encoded character that takes more than one byte to encode.
And even in binary files, knowing the absolute file pointer position can only be useful in a handful situations where, usually, one would be better using a database engine to start with.
tell is tell. It counts the number of bytes from the start of the file to the cursor. \n and \r are bytes, so they get counted. If you want to count the number of bytes, but not count certain characters, you will have to do it manually:
data_read = … # data you have already read
len([b for b in data_read if b not in '\r\n'])
The bad news is that it's far more annoying to do this than just looking at tell. The good news is that it answers both your questions.
or, I suppose you could do
yourfile.tell() - data_read.count('\r') - data_read.count('\n')
result = re.sub("[\r\n]", "", subject)
http://regex101.com/r/kM6dA1
Match a single character present in the list below «[\r\n]»
A carriage return character «\r»
A line feed character «\n»

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

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.

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