Decorate \ delegate a File object to add functionality

后端 未结 5 874
忘掉有多难
忘掉有多难 2020-12-03 01:57

I\'ve been writing a small Python script that executes some shell commands using the subprocess module and a helper function:

import subprocess          


        
5条回答
  •  春和景丽
    2020-12-03 02:35

    This uses Adam Rosenfield's make_async and read_async. Whereas my original answer used select.epoll and was thus Linux-only, it now uses select.select, which should work under Unix or Windows.

    This logs output from the subprocess to /tmp/test.log as it occurs:

    import logging
    import subprocess
    import shlex
    import select
    import fcntl
    import os
    import errno
    
    def make_async(fd):
        # https://stackoverflow.com/a/7730201/190597
        '''add the O_NONBLOCK flag to a file descriptor'''
        fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
    
    def read_async(fd):
        # https://stackoverflow.com/a/7730201/190597
        '''read some data from a file descriptor, ignoring EAGAIN errors'''
        try:
            return fd.read()
        except IOError, e:
            if e.errno != errno.EAGAIN:
                raise e
            else:
                return ''
    
    def log_process(proc,stdout_logger,stderr_logger):
        loggers = { proc.stdout: stdout_logger, proc.stderr:  stderr_logger }
        def log_fds(fds):
            for fd in fds:
                out = read_async(fd)
                if out.strip():
                    loggers[fd].info(out)
        make_async(proc.stdout)
        make_async(proc.stderr)
        while True:
            # Wait for data to become available 
            rlist, wlist, xlist = select.select([proc.stdout, proc.stderr], [], [])
            log_fds(rlist)
            if proc.poll() is not None:
                # Corner case: check if more output was created
                # between the last call to read_async and now
                log_fds([proc.stdout, proc.stderr])                
                break
    
    if __name__=='__main__':
        formatter = logging.Formatter('[%(name)s: %(asctime)s] %(message)s')
        handler = logging.FileHandler('/tmp/test.log','w')
        handler.setFormatter(formatter)
    
        stdout_logger=logging.getLogger('STDOUT')
        stdout_logger.setLevel(logging.DEBUG)
        stdout_logger.addHandler(handler)
    
        stderr_logger=logging.getLogger('STDERR')
        stderr_logger.setLevel(logging.DEBUG)
        stderr_logger.addHandler(handler)        
    
        proc = subprocess.Popen(shlex.split('ls -laR /tmp'),
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        log_process(proc,stdout_logger,stderr_logger)
    

提交回复
热议问题