Just a little context: subprocess
uses raw file descriptors for the stdin, stdout, stderr objects that you specify because it passes them to POSIX . If you use subprocess.PIPE
then it will create a new channel with os.pipe()
. It is also Popen.communicate
read to the end of the stream, which may be undesirable if you want to transfer data somewhere else.
Since you want to print the output to stdout, I assume that it outputs the text. You will need to use encoding
, errors
or universal_newlines
in Popen
for subprocess
to process the file as text (see docs ).
import subprocess
p = subprocess.Popen(
'/usr/bin/whoami',
stdout=subprocess.PIPE,
universal_newlines=True
)
with open('subprocess.log', 'w') as logfile:
while p.poll() is None:
line = p.stdout.readline()
print(line, end='')
logfile.write(line)
stderr, , file=sys.stderr
print
. , stdin, :
subprocess.Popen('/usr/bin/whoami', stdin=sys.stdin, stdout=subprocess.PIPE, ...)
, . , read
.
stderr stdout
stdout, stderr, , .
os.set_blocking
, , read
, . .
, stdout stderr; aysncio
module:
import asyncio
import sys
PROCESS_PATH = '/bin/mixed_output'
class MultiplexProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future):
self.exit_future = exit_future
def pipe_data_received(self, fd, data):
if fd == sys.stdout.fileno():
print(data.decode('utf-8'), file=sys.stdout, end='')
elif fd == sys.stderr.fileno():
print(data.decode('utf-8'), file=sys.stderr, end='')
def process_exited(self):
self.exit_future.set_result(True)
async def launch_subprocess(loop):
exit_future = asyncio.Future(loop=loop)
create_subp = loop.subprocess_exec(
lambda: MultiplexProtocol(exit_future),
PROCESS_PATH,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
stdin=None
)
transport, protocol = await create_subp
await exit_future
transport.close()
loop = asyncio.get_event_loop()
loop.run_until_complete(launch_subprocess(loop))
, - , MultiplexProtocol.pipe_data_received
.