1

I want to write a python script that displays its current progress in the last line of the terminal, similar to how apt (not apt-get) behaves. I know there are ANSI control sequences to interact with the terminal, but the issue is that I want to call other programs (using subprocess) which produce their own output. I don't want these programs to overwrite my progress.

There might be multiple subprocesses running at the same time. I'm using the multithreading module and each thread does some work, then calls and waits for a subprocess, then does cleanup work. I don't mind the output of the subprocesses being mixed, as long as the last line is spared.

When the program exits, the last line should be cleared.

Felix
  • 129
  • 9
  • Possible duplicate of [How do I write output in same place on the console?](https://stackoverflow.com/questions/517127/how-do-i-write-output-in-same-place-on-the-console) – jbndlr Nov 09 '17 at 15:42
  • 1
    This is a little easier if you have the progress line at the top of the terminal. Here's an example I wrote a while ago: https://stackoverflow.com/a/45164619/4014959 But also see https://stackoverflow.com/a/37501797/4014959 – PM 2Ring Nov 09 '17 at 15:46
  • 2
    I highly recommend the [`tqdm`](https://github.com/tqdm/tqdm) library. I believe that it has all the functionality to do what you are asking. – SethMMorton Nov 09 '17 at 15:51
  • @jbndlr Using `\r` _is_ a useful technique, but Felix needs something a little more powerful than that. – PM 2Ring Nov 09 '17 at 16:00
  • I don't think https://stackoverflow.com/questions/517127/how-do-i-write-output-in-same-place-on-the-console is a duplicate; that question describes how to write to the last line. This focuses on segregating subprocess and other output. – Sam Hartman Nov 09 '17 at 21:12
  • Thanks to PM 2Ring, I found a solution. See below. – Felix Nov 10 '17 at 14:10

1 Answers1

5

Thanks to PM 2Ring's comment, I found everything I needed.

The control sequence "\033[X;Yr" (or "\x1b[X;Yr") tells the terminal to only scroll the lines X to Y. I didn't test what happens when X != 0, since I want to keep the scrollback buffer as it is. \033[r resets the terminal to scroll the whole window.

To be dynamic, you should determine the terminal's height, then subtract the number of desired static lines, then set the scrolling range appropriately.

To avoid scrambled output, you should make sure the cursor is not in your static area after setting the scrolling range. For example, your window has the size [w=120,h=40] lines and you want 2 static status lines. Determine the cursor position (e.g. [x=5,y=39]) and if it is within the last two lines of the window, print 2 newlines, then position the cursor at [x=5, y=(h-2)=38].

To update the status area, save the cursor position, move it to the status line, clear the status line, print the status (without trailing newline), restore the cursor position. There are escape sequences to save and restore the position. Clear the status area when you reset the scrolling range.

Helpful links:

Felix
  • 129
  • 9