pythonsubprocessshlex

How to retrive output from python subprocess


I'm using the Python subprocess function, because I want to read the output of the command in real time stream.

But I would like that after the end of process, everything what was written as a stream output was completely returned to object.

import subprocess
import shlex

def run_command(command):
    process = subprocess.Popen(str.split(command), stdout=subprocess.PIPE, stderr = subprocess.PIPE, encoding="utf-8", shell=True)
    while True:
        output = process.stdout.readline()
        if output == '' and process.poll() is not None:
            break
        if output:
            print(output.strip())
    out, err = process.communicate()
    return (process.returncode, out, err)

command_output = run_command("ping 8.8.8.8")
print(command_output)

Actual result:

Pinging 8.8.8.8 with 32 bytes of data:
Reply from 8.8.8.8: bytes=32 time=12ms TTL=57
Reply from 8.8.8.8: bytes=32 time=15ms TTL=57
Reply from 8.8.8.8: bytes=32 time=15ms TTL=57
Reply from 8.8.8.8: bytes=32 time=16ms TTL=57

Ping statistics for 8.8.8.8:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 12ms, Maximum = 16ms, Average = 14ms
(0, '', '')

I only get the status of the code of the completed process. The standard output is empty, but should be contain the all output from processed command.

I use Python 3.7.4

I don't know what to do about it.


Solution

  • You can't read from a pipe multiple times, so calling process.communicate() after it's done will not allow you to read the stdout again.

    You should simply all the output that you read in a string.

    def run_command(command):
        process = subprocess.Popen(str.split(command), stdout=subprocess.PIPE, stderr = subprocess.PIPE, encoding="utf-8", shell=True)
        all_output = ''
        while True:
            output = process.stdout.readline()
            if output == '' and process.poll() is not None:
                break
            if output:
                all_output += output
                print(output.strip())
        out, err = process.communicate()
        return (process.returncode, all_output, err)