2

There are many questions relating to printing on the same line but there aren't any for printing multiple lines on the same line within the terminal.

For example:

ogeno@OH-ogeno-MBP:~|⇒ python my_script.py
Process 1: 5%
Process 2: 14%
Process 3: 55%

I want the progress of these processes to update on the same line rather than printing over and over again. I have looked at other questions that say to use the return carriage character \r and sys.stdout.flush() but it doesn't seem to change the caret to go up a line, just to the end of the current line.

EDIT: My question is different because it's to do with printing MULTIPLE lines on the same lines in the terminal. It's easy if it's just one line.

Ogen
  • 6,499
  • 7
  • 58
  • 124
  • please share a code snippet to see how you are handling this from my_script.py – glls May 31 '16 at 02:37
  • 3
    Possible duplicate of [Python - Rewrite multiple lines in the Console](http://stackoverflow.com/questions/6840420/python-rewrite-multiple-lines-in-the-console) – user2390182 May 31 '16 at 02:38
  • The sane solution to this is to have your controlling process collect the status info and print it. – pvg May 31 '16 at 02:38
  • @glls I'm not handling this. It's just an example of what I want – Ogen May 31 '16 at 02:39
  • @schwobaseggl I'd prefer not to use that curses module. I want to just do it in plain ole python – Ogen May 31 '16 at 02:39
  • @pvg It still needs to be printing in the same console. It doesn't matter which process does it. But the information needs to update ON THE SAME LINE rather than printing again. – Ogen May 31 '16 at 02:40
  • Ok, then what's wrong with http://stackoverflow.com/questions/5598181/python-print-on-same-line – pvg May 31 '16 at 02:41
  • This should be helpful: http://stackoverflow.com/questions/1727155/multiline-progress-bars – user2390182 May 31 '16 at 02:42
  • @pvg It's on one line, which is easy. Mine is multiple lines that need to print on the same line - big difference. – Ogen May 31 '16 at 02:43
  • @schwobaseggl I'll take a look at that, seems like a really dirty workaround though... clearing the entire console :( – Ogen May 31 '16 at 02:43
  • @Ogen I was looking at aaren's solution. But generally, I guess, the system-dependent nature of the task makes it hard in simple good ole Python. – user2390182 May 31 '16 at 02:46
  • @schwobaseggl It's just a shame that it's so easy to do if it's just one line, but a lot harder if it's multiple lines. I thought maybe I'm missing something... – Ogen May 31 '16 at 02:47
  • Right but what is stopping you from collecting the output from multiple lines and printing it on one line? – pvg May 31 '16 at 02:48
  • Is it that you want to repeatedly print on the same line? – pvg May 31 '16 at 02:48
  • @pvg Because it would look ugly all on one line don't you agree? And yes I want to print on the same lines so the user can just see the progress updating in the same place in the terminal – Ogen May 31 '16 at 02:51
  • Ah I see. There is really no platform-independent way to do that. ncurses can cover the unix-y case. – pvg May 31 '16 at 02:54

3 Answers3

1

One approach is to use the ANSI escape-code "\033[F" for going to the beginning of the previous line. The following worked well in all my terminals, just writing to the next two lines from the current terminal position:

import time
import sys

progress_1 = 'Process 1: {}%'
progress_2 = 'Process 2: {}%'
print
print

for i in range(100):
    sys.stdout.write('\033[F')
    sys.stdout.write('\033[F')
    print(progress_1.format(i))
    print(progress_2.format(i))
    time.sleep(0.02)
user2390182
  • 72,016
  • 6
  • 67
  • 89
1

This can easily be done by using backspace. Following is the sample code that will print the percentage on the same line.

import time
print "Work in progress(0%%)", # Python 2 print without newline
for work_done in range(10):
    print "\b\b\b\b\b%2d%%)" % work_done, # Backspace then overwrite
    time.sleep(1)
Hassan Mehmood
  • 1,414
  • 1
  • 14
  • 22
0

for python 2.7 you can use,

print 2%, 3% # Using comma will print it in same line

for python 3.x

print('2%', end=" ")

Or you can use sys.stdout.write for doing it with sys.stdout.flush() Please check my below code, I have created a demo progress bar.

"""ProgressBar Module."""

import sys
import time


class ProgressBar(object):
    """Main class for the ProgressBa."""

    DEFAULT_BAR_LENGTH = float(30)

    def __init__(self, start=0, step=1):
        """Init for the class."""
        self.end = ProgressBar.DEFAULT_BAR_LENGTH
        self.start = start
        self.step = step
        self.total = self.end - self.start
        self.counts = self.total / self.step
        self._barLength = ProgressBar.DEFAULT_BAR_LENGTH

        self.set_level(self.start)
        self._plotted = False

    def set_level_old(self, level, initial=False):
        """Setting Level."""
        self._level = level
        if level < self.start:
            self._level = self.start
        if level > self.end:
            self._level = self.end

        self._ratio = float(
            self._level - self.start) / float(self.end - self.start)
        self._levelChars = int(self._ratio * self._barLength)

    def set_level(self, level, initial=False):
        """Setting Level."""
        self._level = level
        if level < self.start:
            self._level = self.start
        if level > self.end:
            self._level = self.end

        self._ratio = float(self._level) / float(self._barLength)
        self._levelChars = int(self._ratio * self._barLength) * self.step

    def plot_progress(self):
        """Plotting the bar."""
        sys.stdout.write("\r  %3i%%  |%s%s|" % (
            int(self._ratio * self.step * 100.0),
            u'\u2588' * int(self._levelChars),
            ' ' * int(self._barLength - self._levelChars),
        ))
        sys.stdout.flush()
        self._plotted = True

    def set_and_plot(self, level):
        """Call the plot."""
        old_chars = self._levelChars
        self.set_level(level)
        if (not self._plotted) or (old_chars != self._levelChars):
            self.plot_progress()

    def __del__(self):
        """Del for the class."""
        sys.stdout.write("\n")

if __name__ == "__main__":

    pb = ProgressBar(0, 1)

    curProgress = 0
    pb.plot_progress()
    while curProgress <= pb.counts:
        pb.set_and_plot(curProgress)
        curProgress += 1
        time.sleep(0.1)

    del pb
binu.py
  • 1,137
  • 2
  • 9
  • 20