Getting realtime output using subprocess

前端 未结 18 2614
执笔经年
执笔经年 2020-11-22 10:12

I am trying to write a wrapper script for a command line program (svnadmin verify) that will display a nice progress indicator for the operation. This requires me to be abl

相关标签:
18条回答
  • 2020-11-22 11:11

    Complete solution:

    import contextlib
    import subprocess
    
    # Unix, Windows and old Macintosh end-of-line
    newlines = ['\n', '\r\n', '\r']
    def unbuffered(proc, stream='stdout'):
        stream = getattr(proc, stream)
        with contextlib.closing(stream):
            while True:
                out = []
                last = stream.read(1)
                # Don't loop forever
                if last == '' and proc.poll() is not None:
                    break
                while last not in newlines:
                    # Don't loop forever
                    if last == '' and proc.poll() is not None:
                        break
                    out.append(last)
                    last = stream.read(1)
                out = ''.join(out)
                yield out
    
    def example():
        cmd = ['ls', '-l', '/']
        proc = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            # Make all end-of-lines '\n'
            universal_newlines=True,
        )
        for line in unbuffered(proc):
            print line
    
    example()
    
    0 讨论(0)
  • 2020-11-22 11:11

    (This solution has been tested with Python 2.7.15)
    You just need to sys.stdout.flush() after each line read/write:

    while proc.poll() is None:
        line = proc.stdout.readline()
        sys.stdout.write(line)
        # or print(line.strip()), you still need to force the flush.
        sys.stdout.flush()
    
    0 讨论(0)
  • 2020-11-22 11:12

    I ran into the same problem awhile back. My solution was to ditch iterating for the read method, which will return immediately even if your subprocess isn't finished executing, etc.

    0 讨论(0)
  • 2020-11-22 11:12

    Found this "plug-and-play" function here. Worked like a charm!

    import subprocess
    
    def myrun(cmd):
        """from http://blog.kagesenshi.org/2008/02/teeing-python-subprocesspopen-output.html
        """
        p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        stdout = []
        while True:
            line = p.stdout.readline()
            stdout.append(line)
            print line,
            if line == '' and p.poll() != None:
                break
        return ''.join(stdout)
    
    0 讨论(0)
  • 2020-11-22 11:15

    You may use an iterator over each byte in the output of the subprocess. This allows inline update (lines ending with '\r' overwrite previous output line) from the subprocess:

    from subprocess import PIPE, Popen
    
    command = ["my_command", "-my_arg"]
    
    # Open pipe to subprocess
    subprocess = Popen(command, stdout=PIPE, stderr=PIPE)
    
    
    # read each byte of subprocess
    while subprocess.poll() is None:
        for c in iter(lambda: subprocess.stdout.read(1) if subprocess.poll() is None else {}, b''):
            c = c.decode('ascii')
            sys.stdout.write(c)
    sys.stdout.flush()
    
    if subprocess.returncode != 0:
        raise Exception("The subprocess did not terminate correctly.")
    
    0 讨论(0)
  • 2020-11-22 11:16

    if you just want to forward the log to console in realtime

    Below code will work for both

     p = subprocess.Popen(cmd,
                             shell=True,
                             cwd=work_dir,
                             bufsize=1,
                             stdin=subprocess.PIPE,
                             stderr=sys.stderr,
                             stdout=sys.stdout)
    
    0 讨论(0)
提交回复
热议问题