Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@sp3c73r2038
Created June 29, 2016 03:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sp3c73r2038/fa7e30d47b7a9451eeb183a520549561 to your computer and use it in GitHub Desktop.
Save sp3c73r2038/fa7e30d47b7a9451eeb183a520549561 to your computer and use it in GitHub Desktop.
run command in child process without
# -*- coding: utf-8 -*-
import errno
import os
import fcntl
# !! License GPLv2 !!
# only work on Linux, MacOSX, may work on Windows, no tested.
# some syscall/flags not available on other OS(like Solaris), so not supported
def run_in_child(cmd):
"""run shell command in child process,
non-blocking yields output.
Args:
cmd (string): command to run
Returns:
string, int: output line and exit value, output would be ``None'',
exit value should use the last one.
"""
r, w = os.pipe()
pid = os.fork()
exitvalue = None
if pid == 0:
# child
os.dup2(r, 0)
os.dup2(w, 1)
os.dup2(w, 2)
os.close(r)
os.close(w)
os.execl('/bin/bash', 'bash', '-c', cmd)
else:
f = fcntl.fcntl(r, fcntl.F_GETFL)
fcntl.fcntl(r, fcntl.F_SETFL, f | os.O_NONBLOCK)
line = b''
while True:
try:
_ = os.read(r, 1)
line += _
if _ == b'\r':
_ = os.read(r, 1)
line += _
yield line.decode('UTF-8').strip(), exitvalue
line = b''
if _ == b'\n':
yield line.decode('UTF-8').strip(), exitvalue
line = b''
except OSError as e:
try:
if type(e) == BlockingIOError:
pass
else:
raise
except NameError:
if e.errno == errno.EAGAIN:
pass
else:
raise
try:
_pid, exitvalue = os.waitpid(-1, os.WNOHANG)
except Exception as e:
try:
if type(e) == ChildProcessError:
break
else:
raise
except NameError:
if e.errno == errno.ECHILD:
break
else:
raise
if line:
yield line.decode('UTF-8').strip(), exitvalue
yield None, exitvalue
def local(cmd, quiet=False, _raise=True):
"""run local command, prints output non-blocking
Args:
cmd (string): command to run
quiet (bool): whether to surpress output
_raise (bool): whether to raise RuntimeError when exit value is not 0
"""
line = ''
exitvalue = 0
for line, exitvalue in run_in_child(cmd):
if not quiet and line:
print(line)
if exitvalue != 0:
raise RuntimeError('run local command failed: %s' % cmd)
local('python -u sleep.py')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment