Python's subprocess.Popen object hangs gathering child output when child process does not exit

前端 未结 4 1957
既然无缘
既然无缘 2021-01-07 06:16

When a process exits abnormally or not at all, I still want to be able to gather what output it may have generated up until that point.

The obvious solution to this

相关标签:
4条回答
  • 2021-01-07 06:39

    I had the exact same problem. I ended up fixing the issue (after scouring Google and finding many related problems) by simply setting the following parameters when calling subprocess.Popen (or .call):

    stdout=None
    

    and

    stderr=None
    

    There are many problems with these functions but in my specific case I believe stdout was being filled up by the process I was calling and then resulting in a blocking condition. By setting these to None (opposed to something like subprocess.PIPE) I believe this is avoided.

    Hope this helps someone.

    0 讨论(0)
  • 2021-01-07 06:44

    There are good tips in another stackoverflow question: How do I get 'real-time' information back from a subprocess.Popen in python (2.5)

    Most of the hints in there work with pipe.readline() instead of pipe.communicate() because the latter only returns at the end of the process.

    0 讨论(0)
  • 2021-01-07 06:46

    Here's a POSIX way of doing it without the temporary file. I realize that subprocess is a little superfluous here, but since the original question used it...

    import subprocess
    import os
    import time
    import signal
    import sys
    
    pr, pw = os.pipe()
    pid = os.fork () 
    
    if pid: #parent
        os.close(pw)
        cmd = ["bash"]
        finish = time.time() + 3
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=pr, close_fds=True)
        while p.poll() is None:
            time.sleep(0.05)
            if finish < time.time():
                os.kill(p.pid, signal.SIGTERM)
                print "timed out and killed child, collecting what output exists so far"
                out, err = p.communicate()
                print "got it: ", out
                sys.exit(0)
    
    else: #child
        os.close(pr)
        child_script = """
        #!/bin/bash
        while [ 1 ]; do
            ((++i))
            echo "output line $i"
            sleep 1
        done
        """
        os.write(pw, child_script)
    
    0 讨论(0)
  • 2021-01-07 06:52

    Problem is that bash doesn't answer to CTRL-C when not connected with a terminal. Switching to SIGHUP or SIGTERM seems to do the trick:

    cmd = ["bash", 'childProc.sh']
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                              stderr=subprocess.STDOUT, 
                              close_fds=True)
    time.sleep(3)
    print 'killing pid', p.pid
    os.kill(p.pid, signal.SIGTERM)
    print "timed out and killed child, collecting what output exists so far"
    out  = p.communicate()[0]
    print "got it", out
    

    Outputs:

    killing pid 5844
    timed out and killed child, collecting what output exists so far
    got it output line 0
    output line 1
    output line 2
    
    0 讨论(0)
提交回复
热议问题