Redirect subprocess stderr to stdout

53,861

Solution 1

A close read of the source code gives the answer. In particular, the documentation is misleading when it says:

subprocess.STDOUT
Special value that (...) indicates that standard error should go into the same handle as standard output.

Since stdout is set to "default" (-1, technically) when stderr=subprocess.STDOUT is evaluated, stderr is set to "default" as well. Unfortunately, this means that stderr output still goes to stderr.

To solve the problem, pass in the stdout file instead of subprocess.STDOUT:

$ python >/dev/null -c 'import subprocess,sys;subprocess.call(["ls", "/404"],
                        stderr=sys.stdout.buffer)'

Or, for compatibility with legacy 2.x versions of Python:

$ python >/dev/null -c 'import subprocess,sys;subprocess.call(["ls", "/404"],
                        stderr=sys.stdout.fileno())'

Solution 2

Actually, using subprocess.STDOUT does exactly what is stated in the documentation: it redirects stderr to stdout so that e.g.

proc = subprocess.Popen(self.task["command"], shell=False, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = ""
while (True):
    # Read line from stdout, break if EOF reached, append line to output
    line = proc.stdout.readline()
    line = line.decode()
    if (line == ""): break
    output += line

results in variable output containing the process' output from both stdout and stderr.

stderr=subprocess.STDOUT redirects all stderr output directly to stdout of the calling process, which is a major difference.

Share:
53,861
phihag
Author by

phihag

Hi, I'm Philipp Hagemeister. You can contact me at [email protected] or a number of other communication channels.

Updated on July 09, 2022

Comments

  • phihag
    phihag almost 2 years

    I want to redirect the stderr output of a subprocess to stdout. The constant STDOUT should do that, shouldn't it?

    However,

    $ python >/dev/null -c 'import subprocess;\
                            subprocess.call(["ls", "/404"],stderr=subprocess.STDOUT)'
    

    does output something. Why is that the case, and how do I get the error message on stdout?

  • phihag
    phihag about 11 years
    -1 This case is irrelevant to the question which is about stdout being None. And subprocess.STDOUT does not redirect to the "calling console" (I think you mean the file handle 1 that the current process was given), as your own example shows - if you call Popen with ['ls', '/404'], the error message is not displayed.
  • Fonic
    Fonic almost 10 years
    You are somewhat right. However, I don't think that this is irrelevant at all, since this is intended to clarify your post regarding the documentation being misleading - which isn't the case. I would have left a comment below your post, but a year ago I wasn't allowed to do so.
  • Mike S
    Mike S almost 9 years
    python -c 'import subprocess,sys;subprocess.call(["ls", "/404"], stderr=subprocess.STDOUT)' 2>/dev/null shows that the stderr of ls goes to stderr (file descriptor 2) because you will not see any output (presuming you have no /404 on your system). That Python documentation really whiffed on that topic, and it's especially annoying to us shell scripters who are used to manipulating stdout/stderr in myriads of ways, and have to come here to SO just to figure out how to do something which should be simple and non-confusing.
  • Mike S
    Mike S almost 9 years
    One can leave stderr as-is too: stderr=sys.stderr.fileno() . Nice example; I am going to simply use this technique in all my scripts. We have legacy Python 2.x; thus I'll know exactly where I told it to go without confusion.
  • Ray Salemi
    Ray Salemi almost 7 years
    It seems to me that the above here is the simpler solution and the intention of the OP.
  • ipetrik
    ipetrik over 3 years
    For the record this is no-longer necessary in python 3.5+, as this case is automatically handled: github.com/python/cpython/blob/…