9

Possible Duplicate:
subprocess with timeout

What is the easiest way to do the following in Python:

  • Run an external process
  • Capture stdout in a string, stderr, and exit status
  • Set a timeout.

I would like something like this:

import proc

try:
    status, stdout, stderr = proc.run(["ls", "-l"], timeout=10)
except proc.Timeout:
    print "failed"
Community
  • 1
  • 1
flybywire
  • 232,954
  • 184
  • 384
  • 491

2 Answers2

13

I hate doing the work by myself. Just copy this into your proc.py module.

import subprocess
import time
import sys

class Timeout(Exception):
    pass

def run(command, timeout=10):
    proc = subprocess.Popen(command, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poll_seconds = .250
    deadline = time.time()+timeout
    while time.time() < deadline and proc.poll() == None:
        time.sleep(poll_seconds)

    if proc.poll() == None:
        if float(sys.version[:3]) >= 2.6:
            proc.terminate()
        raise Timeout()

    stdout, stderr = proc.communicate()
    return stdout, stderr, proc.returncode

if __name__=="__main__":
    print run(["ls", "-l"])
    print run(["find", "/"], timeout=3) #should timeout
flybywire
  • 232,954
  • 184
  • 384
  • 491
  • 1
    This version might timeout due to pipe buffer overflow (when stdout or stderr ~64K). – jfs Oct 12 '09 at 22:19
  • 1
    If the command times out, you won't get any output generated up to the timeout. – Mike Mazur Oct 13 '09 at 01:57
  • print run(["ping www.redicecn.com"], timeout=10),the script threw out Timeout exception, but the ping process was still running. – redice Sep 06 '12 at 12:33
12

Note on linux with coreutils >= 7.0 you can prepend timeout to the command like:

timeout 1 sleep 1000
pixelbeat
  • 27,785
  • 9
  • 47
  • 57