Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Capture stdout from subprocess.call

Tags:

python

I'm trying to do two things when executing a shell cmd with Python:

  • Capture stdout and print it as it happens
  • Capture stdout as a whole and process it when the cmd is complete

I looked at subprocess.check_output, but it does not have an stdout param that would allow me to print the output as it happens.

So after reading this question, I realized I may need to try a different approach.

from subprocess import Popen, PIPE

process = Popen(task_cmd, stdout = PIPE)
stdout, stderr = process.communicate()

print(stdout, stderr)

The problem with this approach is that according to the docs, Popen.communicate():

Reads data from stdout and stderr, until end-of-file is reached. Wait for process to terminate

I still cannot seem to redirect output both to stdout AND to some sort of buffer that can be parsed when the command is complete.

Ideally, I'd like something like:

# captures the process output and dumps it to stdout in realtime
stdout_capture = Something(prints_to_stdout = True)
process = Popen(task_cmd, stdout = stdout_capture)

# prints the entire output of the executed process
print(stdout_capture.complete_capture)

Is there a recommended way to accomplish this?

like image 993
doremi Avatar asked Mar 07 '17 18:03

doremi


People also ask

How do I get stdout from 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.

How do I get the output of a subprocess call?

communicate() #Another way to get output #output = subprocess. Popen(args,stdout = subprocess. PIPE). stdout ber = raw_input("search complete, display results?") print output #... and on to the selection process ...

How do you read subprocess Popen output?

popen. To run a process and read all of its output, set the stdout value to PIPE and call communicate(). The above script will wait for the process to complete and then it will display the output.

What does Python subprocess call return?

Return Value of the Call() Method from Subprocess in Python The Python subprocess call() function returns the executed code of the program. If there is no program output, the function will return the code that it executed successfully. It may also raise a CalledProcessError exception.


1 Answers

You were on the right track with using giving Popen stdout=PIPE, but you can't use .communicate() because it returns the values after execution. Instead, I suggest you read from .stdout.

The only guaranteed way to get the output the moment it's generated is to read from the pipe one character at a time. Here is my approach:

def passthrough_and_capture_output(args):
    import sys
    import subprocess

    process = subprocess.Popen(args, stdout=subprocess.PIPE, universal_newlines=True)
    # universal_newlines means that the output of the process will be interpreted as text
    capture = ""

    s = process.stdout.read(1)
    while len(s) > 0:
        sys.stdout.write(s)
        sys.stdout.flush()
        capture += s
        s = process.stdout.read(1)

    return capture

Note that reading one character at a time can incur significant overhead, so if you are alright with lagging behind a bit, I suggest that you replace the 1 in read(1) with a different number of characters to output in batches.

like image 105
timotree Avatar answered Oct 02 '22 15:10

timotree