Using module 'subprocess' with timeout

后端 未结 29 2395
旧巷少年郎
旧巷少年郎 2020-11-21 15:15

Here\'s the Python code to run an arbitrary command returning its stdout data, or raise an exception on non-zero exit codes:

proc = subprocess.P         


        
相关标签:
29条回答
  • 2020-11-21 15:59

    In Python 3.3+:

    from subprocess import STDOUT, check_output
    
    output = check_output(cmd, stderr=STDOUT, timeout=seconds)
    

    output is a byte string that contains command's merged stdout, stderr data.

    check_output raises CalledProcessError on non-zero exit status as specified in the question's text unlike proc.communicate() method.

    I've removed shell=True because it is often used unnecessarily. You can always add it back if cmd indeed requires it. If you add shell=True i.e., if the child process spawns its own descendants; check_output() can return much later than the timeout indicates, see Subprocess timeout failure.

    The timeout feature is available on Python 2.x via the subprocess32 backport of the 3.2+ subprocess module.

    0 讨论(0)
  • 2020-11-21 16:00

    I added the solution with threading from jcollado to my Python module easyprocess.

    Install:

    pip install easyprocess
    

    Example:

    from easyprocess import Proc
    
    # shell is not supported!
    stdout=Proc('ping localhost').call(timeout=1.5).stdout
    print stdout
    
    0 讨论(0)
  • 2020-11-21 16:01

    The solution I use is to prefix the shell command with timelimit. If the comand takes too long, timelimit will stop it and Popen will have a returncode set by timelimit. If it is > 128, it means timelimit killed the process.

    See also python subprocess with timeout and large output (>64K)

    0 讨论(0)
  • 2020-11-21 16:02

    if you are using python 2, give it a try

    import subprocess32
    
    try:
        output = subprocess32.check_output(command, shell=True, timeout=3)
    except subprocess32.TimeoutExpired as e:
        print e
    
    0 讨论(0)
  • 2020-11-21 16:02

    I've implemented what I could gather from a few of these. This works in Windows, and since this is a community wiki, I figure I would share my code as well:

    class Command(threading.Thread):
        def __init__(self, cmd, outFile, errFile, timeout):
            threading.Thread.__init__(self)
            self.cmd = cmd
            self.process = None
            self.outFile = outFile
            self.errFile = errFile
            self.timed_out = False
            self.timeout = timeout
    
        def run(self):
            self.process = subprocess.Popen(self.cmd, stdout = self.outFile, \
                stderr = self.errFile)
    
            while (self.process.poll() is None and self.timeout > 0):
                time.sleep(1)
                self.timeout -= 1
    
            if not self.timeout > 0:
                self.process.terminate()
                self.timed_out = True
            else:
                self.timed_out = False
    

    Then from another class or file:

            outFile =  tempfile.SpooledTemporaryFile()
            errFile =   tempfile.SpooledTemporaryFile()
    
            executor = command.Command(c, outFile, errFile, timeout)
            executor.daemon = True
            executor.start()
    
            executor.join()
            if executor.timed_out:
                out = 'timed out'
            else:
                outFile.seek(0)
                errFile.seek(0)
                out = outFile.read()
                err = errFile.read()
    
            outFile.close()
            errFile.close()
    
    0 讨论(0)
  • 2020-11-21 16:04

    Prepending the Linux command timeout isn't a bad workaround and it worked for me.

    cmd = "timeout 20 "+ cmd
    subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (output, err) = p.communicate()
    
    0 讨论(0)
提交回复
热议问题