python subprocess.Popen - write to stderr

2019-09-10 03:10发布

问题:

I have a c program (I'm not the author) that reads from stderr. I call it using subprocess.Popen as below. Is there any way to write to stderr of the subprocess.

proc = subprocess.Popen(['./std.bin'],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

回答1:

Yes, maybe, but you should be aware of the irregularity of writing to the standard output or standard error output of a subprocess. The vast majority of processes only writes to these and almost none is actually trying to read (because in almost all cases there's nothing to read).

What you could try is to open a socket and supply that as the stderr argument.

What you most probably want to do is the opposite, to read from the stderr from the subprocess (the subprocesses writes, you read). That can be done by just setting it to subprocess.PIPE and then access the stderr attribute of the subprocess:

proc subprocess(['./std.bin'], stderr=subprocess.PIPE)

for l in proc.stderr:
     print(l)

Note that you could specify more than one of stdin, stdout and stderr as being subprocess.PIPE. This will not mean that they will be connected to the same pipe (subprocess.PIPE is no actuall file, but just a placeholder to indicate that a pipe should be created). If you do this however you should take care to avoid deadlocks, this can for example be done by using the communicate method (you can inspect the source of the subprocess module to see what communicate does if you want to do it yourself).



回答2:

If the child process reads from stderr (note: normally stderr is opened for output):

#!/usr/bin/env python
"""Read from *stderr*, write to *stdout* reversed bytes."""
import os

os.write(1, os.read(2, 512)[::-1])

then you could provide a pseudo-tty (so that all streams point to the same place), to work with the child as if it were a normal subprocess:

#!/usr/bin/env python
import sys
import pexpect # $ pip install pexpect

child = pexpect.spawnu(sys.executable, ['child.py'])
child.sendline('abc') # write to the child
child.expect(pexpect.EOF)
print(repr(child.before))
child.close()

Output

u'abc\r\n\r\ncba'

You could also use subprocess + pty.openpty() instead pexpect.

Or you could write a code specific to the weird stderr behavior:

#!/usr/bin/env python
import os
import sys
from subprocess import Popen, PIPE

r, w = os.pipe()
p = Popen([sys.executable, 'child.py'], stderr=r, stdout=PIPE,
          universal_newlines=True)
os.close(r)
os.write(w, b'abc') # write to subprocess' stderr
os.close(w)
print(repr(p.communicate()[0]))

Output

'cba'


回答3:

for line in proc.stderr:
    sys.stdout.write(line)

This is write the stderr of the subprocess. Hope it answers your question.