Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real time output of subprocess.popen() and not line by line

I'm currently rewriting a little wrapper program in python that I once wrote in C++. It extracts files from a file and boxes them in another format.

In C++ the output from the system commands I need to run was "real time" i.e the status bar and the percentage indicator of some commands where shown in real time. With python I get each 'percent' dumped on the screen individually (because I read it line by line). Here's an example: Thats how a status bar looks in the python version (this goes on until 100). In C++ it does update itself though.

| (02/100)\rImporting AVC-H264: |                    | (03/100)\rImporting AVC-H264: |                       | (04/100)\rImporting AVC-H264: |=

Thats the corresponding python code:

p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
for line in iter(p.stdout.readline, ""):
   print line,

Any ideas on how I could make it look like in C++ ?

like image 700
Basil Avatar asked Jan 06 '11 22:01

Basil


People also ask

What does subprocess Popen return?

Popen Function The function should return a pointer to a stream that may be used to read from or write to the pipe while also creating a pipe between the calling application and the executed command. Immediately after starting, the Popen function returns data, and it does not wait for the subprocess to finish.

What is the difference between subprocess run and Popen?

The main difference is that subprocess. run() executes a command and waits for it to finish, while with subprocess. Popen you can continue doing your stuff while the process finishes and then just repeatedly call Popen. communicate() yourself to pass and receive data to your process.

What does Popen return Python?

Returned value If successful, popen() returns a pointer to an open stream that can be used to read or write to a pipe. If unsuccessful, popen() returns a NULL pointer and sets errno to one of the following values: Error Code. Description.

How do I capture the output of a subprocess run?

To capture the output of the subprocess. run method, use an additional argument named “capture_output=True”. You can individually access stdout and stderr values by using “output. stdout” and “output.


2 Answers

Could be two things...

It's likely that readline is changing some things from the output of your program. I believe \r is carriage return and tells the terminal to return to the beginning of the line and then the program can output overtop the text it just output. Readline is most likely removing this.

First thing to try,

p = subprocess.Popen(args, stdout=subprocess.PIPE, \
                     stderr=subprocess.PIPE, \
                     universal_newlines=True)
for line in iter(p.stdout.readline, ""):
    sys.stdout.write('\r'+line[:-1])
    sys.stdout.flush()

You have to do the flush because stdout buffers until it gets a \n and of course you're not writing one.

like image 154
milkypostman Avatar answered Nov 14 '22 23:11

milkypostman


On Windows, you can output the backspace character (ASCII code 8). Example (prints the current iteration using only single digit numbers):

>>> import time
>>> import sys
>>> for i in xrange(10):
...     sys.stdout.write(str(i))
...     time.sleep(.5)
...     sys.stdout.write(chr(8))
...

You would need to keep track of the number of characters on the current line... I'm sure there must be a better way.

On Linux, it appears that you can write carriage returns to reset the cursor position. See Erase the current printed console line and In-place progress output in the terminal or console.

like image 30
Jeremy Brown Avatar answered Nov 14 '22 23:11

Jeremy Brown