Having difficulty capturing output of a subprocess

2019-07-04 21:33发布

问题:

So I'm trying to capture the output of HandBrakeCLI as a Python subprocess. This is not a problem with stderr as each update creates a new line in the file-like pipe. However, with stdout, HandBrakeCLI makes in-place updates and I'm having difficulty capturing them. I'm not even ure what the in-place updates are called, which makes finding relevant tips a bit tricky.

The only solution I've come up with thus far is to write the stdout to an actual file and read from that, but I'd rather do this the sane way (in memory).

COMMAND = ['HandBrakeCLI', '-v', '-i', 'in.m4v', '-o', 'out.m4v', '-Z', 'Normal']

outfile = open('output.txt', 'w')

proc = subprocess.Popen(COMMAND, stdout=outfile, stderr=subprocess.PIPE)

infile = open('output.txt', 'r')

while proc.poll() is None:
    print infile.read()
    infile.seek(0)

This works, but there must be a better way. When attempting to use communicate() or just plain proc.stdout.read() I get nothing.

What am I doing wrong? Thanks!

Update

Per @wim suggestion I checked to see what the raw output HandBrakeCLI provided and it looked something like this:

\rEncoding: task 1 of 1, 0.15 %

What is the best way to handle a stdout that is prefixed with a \r?

回答1:

I think the comment I made above about using universal_newlines=True will work.

Here's a sample in-place writer, called "inplace_output.py"

import sys
import time


def main():
    for k in range(5):
        print "{0:03d}\r".format(k),
        sys.stdout.flush()
        time.sleep(1)

if __name__ == "__main__":
    main()

You can run that, and watch it write 000, then 001, etc, each time overwriting the previous output.

Here's a script that runs the above as a subprocess, and reads its output line by line:

import subprocess


cmd = ['python', 'inplace_output.py']

proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True)

while True:
    out = proc.stdout.readline()
    print repr(out)
    if len(out) == 0:
        break

If want to collect all the output at once when the subprocess program terminates, you can replace the while loop with, say,

out, err = proc.communicate()
lines = out.splitlines()

Does either of those work for you?