To get a string as output, use “output. stdout. decode(“utf-8”)” method. You can also supply “text=True” as an extra argument to the subprocess.
RETURN VALUE Upon successful completion, popen() shall return a pointer to an open stream that can be used to read or write to the pipe. Otherwise, it shall return a null pointer and may set errno to indicate the error.
The subprocess. popen() is one of the most useful methods which is used to create a process. This process can be used to run a command or execute binary. The process creation is also called as spawning a new process which is different from the current process.
Popen is more general than subprocess. call . Popen doesn't block, allowing you to interact with the process while it's running, or continue with other things in your Python program. The call to Popen returns a Popen object.
TLDR for Python 3:
import subprocess
import sys
with open('test.log', 'wb') as f:
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for c in iter(lambda: process.stdout.read(1), b''):
sys.stdout.buffer.write(c)
f.buffer.write(c)
You have two ways of doing this, either by creating an iterator from the read
or readline
functions and do:
import subprocess
import sys
with open('test.log', 'w') as f: # replace 'w' with 'wb' for Python 3
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for c in iter(lambda: process.stdout.read(1), ''): # replace '' with b'' for Python 3
sys.stdout.write(c)
f.write(c)
or
import subprocess
import sys
with open('test.log', 'w') as f: # replace 'w' with 'wb' for Python 3
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for line in iter(process.stdout.readline, ''): # replace '' with b'' for Python 3
sys.stdout.write(line)
f.write(line)
Or you can create a reader
and a writer
file. Pass the writer
to the Popen
and read from the reader
import io
import time
import subprocess
import sys
filename = 'test.log'
with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader:
process = subprocess.Popen(command, stdout=writer)
while process.poll() is None:
sys.stdout.write(reader.read())
time.sleep(0.5)
# Read the remaining
sys.stdout.write(reader.read())
This way you will have the data written in the test.log
as well as on the standard output.
The only advantage of the file approach is that your code doesn't block. So you can do whatever you want in the meantime and read whenever you want from the reader
in a non-blocking way. When you use PIPE
, read
and readline
functions will block until either one character is written to the pipe or a line is written to the pipe respectively.
subprocess.PIPE
, otherwise it's hard.It may be time to explain a bit about how subprocess.Popen
does its thing.
(Caveat: this is for Python 2.x, although 3.x is similar; and I'm quite fuzzy on the Windows variant. I understand the POSIX stuff much better.)
The Popen
function needs to deal with zero-to-three I/O streams, somewhat simultaneously. These are denoted stdin
, stdout
, and stderr
as usual.
You can provide:
None
, indicating that you don't want to redirect the stream. It will inherit these as usual instead. Note that on POSIX systems, at least, this does not mean it will use Python's sys.stdout
, just Python's actual stdout; see demo at end.int
value. This is a "raw" file descriptor (in POSIX at least). (Side note: PIPE
and STDOUT
are actually int
s internally, but are "impossible" descriptors, -1 and -2.)fileno
method. Popen
will find the descriptor for that stream, using stream.fileno()
, and then proceed as for an int
value.subprocess.PIPE
, indicating that Python should create a pipe.subprocess.STDOUT
(for stderr
only): tell Python to use the same descriptor as for stdout
. This only makes sense if you provided a (non-None
) value for stdout
, and even then, it is only needed if you set stdout=subprocess.PIPE
. (Otherwise you can just provide the same argument you provided for stdout
, e.g., Popen(..., stdout=stream, stderr=stream)
.)If you redirect nothing (leave all three as the default None
value or supply explicit None
), Pipe
has it quite easy. It just needs to spin off the subprocess and let it run. Or, if you redirect to a non-PIPE
—an int
or a stream's fileno()
—it's still easy, as the OS does all the work. Python just needs to spin off the subprocess, connecting its stdin, stdout, and/or stderr to the provided file descriptors.
If you redirect only one stream, Pipe
still has things pretty easy. Let's pick one stream at a time and watch.
Suppose you want to supply some stdin
, but let stdout
and stderr
go un-redirected, or go to a file descriptor. As the parent process, your Python program simply needs to use write()
to send data down the pipe. You can do this yourself, e.g.:
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
proc.stdin.write('here, have some data\n') # etc
or you can pass the stdin data to proc.communicate()
, which then does the stdin.write
shown above. There is no output coming back so communicate()
has only one other real job: it also closes the pipe for you. (If you don't call proc.communicate()
you must call proc.stdin.close()
to close the pipe, so that the subprocess knows there is no more data coming through.)
Suppose you want to capture stdout
but leave stdin
and stderr
alone. Again, it's easy: just call proc.stdout.read()
(or equivalent) until there is no more output. Since proc.stdout()
is a normal Python I/O stream you can use all the normal constructs on it, like:
for line in proc.stdout:
or, again, you can use proc.communicate()
, which simply does the read()
for you.
If you want to capture only stderr
, it works the same as with stdout
.
There's one more trick before things get hard. Suppose you want to capture stdout
, and also capture stderr
but on the same pipe as stdout:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
In this case, subprocess
"cheats"! Well, it has to do this, so it's not really cheating: it starts the subprocess with both its stdout and its stderr directed into the (single) pipe-descriptor that feeds back to its parent (Python) process. On the parent side, there's again only a single pipe-descriptor for reading the output. All the "stderr" output shows up in proc.stdout
, and if you call proc.communicate()
, the stderr result (second value in the tuple) will be None
, not a string.
The problems all come about when you want to use at least two pipes. In fact, the subprocess
code itself has this bit:
def communicate(self, input=None):
...
# Optimization: If we are only using one pipe, or no pipe at
# all, using select() or threads is unnecessary.
if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
But, alas, here we've made at least two, and maybe three, different pipes, so the count(None)
returns either 1 or 0. We must do things the hard way.
On Windows, this uses threading.Thread
to accumulate results for self.stdout
and self.stderr
, and has the parent thread deliver self.stdin
input data (and then close the pipe).
On POSIX, this uses poll
if available, otherwise select
, to accumulate output and deliver stdin input. All this runs in the (single) parent process/thread.
Threads or poll/select are needed here to avoid deadlock. Suppose, for instance, that we've redirected all three streams to three separate pipes. Suppose further that there's a small limit on how much data can be stuffed into to a pipe before the writing process is suspended, waiting for the reading process to "clean out" the pipe from the other end. Let's set that small limit to a single byte, just for illustration. (This is in fact how things work, except that the limit is much bigger than one byte.)
If the parent (Python) process tries to write several bytes—say, 'go\n'
to proc.stdin
, the first byte goes in and then the second causes the Python process to suspend, waiting for the subprocess to read the first byte, emptying the pipe.
Meanwhile, suppose the subprocess decides to print a friendly "Hello! Don't Panic!" greeting. The H
goes into its stdout pipe, but the e
causes it to suspend, waiting for its parent to read that H
, emptying the stdout pipe.
Now we're stuck: the Python process is asleep, waiting to finish saying "go", and the subprocess is also asleep, waiting to finish saying "Hello! Don't Panic!".
The subprocess.Popen
code avoids this problem with threading-or-select/poll. When bytes can go over the pipes, they go. When they can't, only a thread (not the whole process) has to sleep—or, in the case of select/poll, the Python process waits simultaneously for "can write" or "data available", writes to the process's stdin only when there is room, and reads its stdout and/or stderr only when data are ready. The proc.communicate()
code (actually _communicate
where the hairy cases are handled) returns once all stdin data (if any) have been sent and all stdout and/or stderr data have been accumulated.
If you want to read both stdout
and stderr
on two different pipes (regardless of any stdin
redirection), you will need to avoid deadlock too. The deadlock scenario here is different—it occurs when the subprocess writes something long to stderr
while you're pulling data from stdout
, or vice versa—but it's still there.
I promised to demonstrate that, un-redirected, Python subprocess
es write to the underlying stdout, not sys.stdout
. So, here is some code:
from cStringIO import StringIO
import os
import subprocess
import sys
def show1():
print 'start show1'
save = sys.stdout
sys.stdout = StringIO()
print 'sys.stdout being buffered'
proc = subprocess.Popen(['echo', 'hello'])
proc.wait()
in_stdout = sys.stdout.getvalue()
sys.stdout = save
print 'in buffer:', in_stdout
def show2():
print 'start show2'
save = sys.stdout
sys.stdout = open(os.devnull, 'w')
print 'after redirect sys.stdout'
proc = subprocess.Popen(['echo', 'hello'])
proc.wait()
sys.stdout = save
show1()
show2()
When run:
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered
start show2
hello
Note that the first routine will fail if you add stdout=sys.stdout
, as a StringIO
object has no fileno
. The second will omit the hello
if you add stdout=sys.stdout
since sys.stdout
has been redirected to os.devnull
.
(If you redirect Python's file-descriptor-1, the subprocess will follow that redirection. The open(os.devnull, 'w')
call produces a stream whose fileno()
is greater than 2.)
We can also use the default file iterator for reading stdout instead of using iter construct with readline().
import subprocess
import sys
process = subprocess.Popen(your_command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in process.stdout:
sys.stdout.write(line)
In addition to all these answer, one simple approach could also be as follows:
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
while process.stdout.readable():
line = process.stdout.readline()
if not line:
break
print(line.strip())
Loop through the readable stream as long as it's readable and if it gets an empty result, stop.
The key here is that readline()
returns a line (with \n
at the end) as long as there's an output and empty if it's really at the end.
Hope this helps someone.
If you're able to use third-party libraries, You might be able to use something like sarge
(disclosure: I'm its maintainer). This library allows non-blocking access to output streams from subprocesses - it's layered over the subprocess
module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With