How to read the first byte of a subprocess's stdout and then discard the rest in Python?

后端 未结 2 1092
小鲜肉
小鲜肉 2020-12-05 06:43

I\'d like to read the first byte of a subprocess\' stdout to know that it has started running. After that I\'d like to discard all further output, so that I don\'t have to w

相关标签:
2条回答
  • 2020-12-05 07:24

    This seems to work, but it doesn't feel idiomatic.

    #!/usr/bin/env python3.1
    import threading
    import subprocess
    
    def discard_stream_while_running(stream, process):
        while process.poll() is None:
            stream.read(1024)
    
    def discard_subprocess_pipes(process, out=True, err=True, in_=True):
        if out and process.stdout is not None and not process.stdout.closed:
            t = threading.Thread(target=discard_stream_while_running, args=(process.stdout, process))
            t.start()
    
        if err and process.stderr is not None and not process.stderr.closed:
            u = threading.Thread(target=discard_stream_while_running, args=(process.stderr, process))
            u.start()
    
        if in_ and process.stdin is not None and not process.stdin.closed:
            process.stdin.close()
    

    Example/test usage

    if __name__ == "__main__":
        import tempfile
        import textwrap
        import time
    
        with tempfile.NamedTemporaryFile("w+t", prefix="example-", suffix=".py") as f:
            f.write(textwrap.dedent("""
                import sys
                import time
    
                sys.stderr.write("{} byte(s) read through stdin.\\n"
                                 .format(len(sys.stdin.read())))
    
                # Push a couple of MB/s to stdout, messages to stderr.
                while True:
                    sys.stdout.write("Hello Parent\\n" * 1000000)
                    sys.stderr.write("Subprocess Writing Data\\n")
                    time.sleep(0.5)
            """))
            f.flush()
    
            p = subprocess.Popen(["python3.1", f.name],
                                 stdout=subprocess.PIPE,
                                 stdin=subprocess.PIPE)
    
            p.stdin.write("Hello Child\n".encode())
    
            discard_subprocess_pipes(p) # <-- Here
    
            for s in range(16, 0, -1):
                print("Main Process Running For", s, "More Seconds")
                time.sleep(1)
    
    0 讨论(0)
  • 2020-12-05 07:31

    If you're using Python 3.3+, you can use the DEVNULL special value for stdout and stderr to discard subprocess output.

    from subprocess import Popen, DEVNULL
    
    process = Popen(["mycmd", "myarg"], stdout=DEVNULL, stderr=DEVNULL)
    

    Or if you're using Python 2.4+, you can simulate this with:

    import os
    from subprocess import Popen
    
    DEVNULL = open(os.devnull, 'wb')
    process = Popen(["mycmd", "myarg"], stdout=DEVNULL, stderr=DEVNULL)
    

    However this doesn't give you the opportunity to read the first byte of stdout.

    0 讨论(0)
提交回复
热议问题