Skip to content

Instantly share code, notes, and snippets.

@mckaydavis
Created June 23, 2014 21:50
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mckaydavis/e96c1637d02bcf8a78e7 to your computer and use it in GitHub Desktop.
Save mckaydavis/e96c1637d02bcf8a78e7 to your computer and use it in GitHub Desktop.
Python non-blocking reading from stdout and stderr of subprocess.popen process using os.pipe and select.select
#!/usr/bin/env python
# File: log_exec.py
# Author: McKay Davis
# Date: Jun 23, 2014
# Non-blocking stdout and stderr read from a
# Popen process
import os
import subprocess
import select
def log_exec(args, env = None, log = None):
'''
execute command and log process stdout and stderr
to file-object 'log' while simultaneously logging to stdout
'''
exec_env = {}
exec_env.update(os.environ)
# copy the OS environment into our local environment
if env is not None:
exec_env.update(env)
# create a pipe to receive stdout and stderr from process
(pipe_r, pipe_w) = os.pipe()
p = subprocess.Popen(args,
shell = False,
env = exec_env,
stdout = pipe_w,
stderr = pipe_w)
# Loop while the process is executing
while p.poll() is None:
# Loop long as the selct mechanism indicates there
# is data to be read from the buffer
while len(select.select([pipe_r], [], [], 0)[0]) == 1:
# Read up to a 1 KB chunk of data
buf = os.read(pipe_r, 1024)
# Stream data to our stdout's fd of 0
os.write(0, buf)
if log is not None:
log.write(buf)
# cleanup
os.close(pipe_r)
os.close(pipe_w)
# return the result of the process
return p.returncode
# Test by running 'log_exec.py log.txt <cmd>'
if __name__ == "__main__":
import sys
log_exec(sys.argv[2:], log=open(sys.argv[1], "wb"))
@phizaz
Copy link

phizaz commented Jan 20, 2018

Thank you so much! Found this finally after hours of googling!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment