Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read streaming input from subprocess.communicate()

I'm using Python's subprocess.communicate() to read stdout from a process that runs for about a minute.

How can I print out each line of that process's stdout in a streaming fashion, so that I can see the output as it's generated, but still block on the process terminating before continuing?

subprocess.communicate() appears to give all the output at once.

like image 954
Heinrich Schmetterling Avatar asked Apr 26 '10 18:04

Heinrich Schmetterling


People also ask

How do I get output to run from subprocess?

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.

What is communicate in subprocess?

. communicate() writes input (there is no input in this case so it just closes subprocess' stdin to indicate to the subprocess that there is no more input), reads all output, and waits for the subprocess to exit.

What is subprocess popen ()?

The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.

What is the output of subprocess Check_output?

The subprocess. check_output() is used to get the output of the calling program in python. It has 5 arguments; args, stdin, stderr, shell, universal_newlines. The args argument holds the commands that are to be passed as a string.


1 Answers

To get subprocess' output line by line as soon as the subprocess flushes its stdout buffer:

#!/usr/bin/env python2 from subprocess import Popen, PIPE  p = Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1) with p.stdout:     for line in iter(p.stdout.readline, b''):         print line, p.wait() # wait for the subprocess to exit 

iter() is used to read lines as soon as they are written to workaround the read-ahead bug in Python 2.

If subprocess' stdout uses a block buffering instead of a line buffering in non-interactive mode (that leads to a delay in the output until the child's buffer is full or flushed explicitly by the child) then you could try to force an unbuffered output using pexpect, pty modules or unbuffer, stdbuf, script utilities, see Q: Why not just use a pipe (popen())?


Here's Python 3 code:

#!/usr/bin/env python3 from subprocess import Popen, PIPE  with Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1,            universal_newlines=True) as p:     for line in p.stdout:         print(line, end='') 

Note: Unlike Python 2 that outputs subprocess' bytestrings as is; Python 3 uses text mode (cmd's output is decoded using locale.getpreferredencoding(False) encoding).

like image 65
jfs Avatar answered Sep 22 '22 19:09

jfs