在subprocess.check_output中添加超时

时间:2015-04-15 11:31:56

标签: python subprocess

我正在使用Python 2.7开发一个小工具并使用子进程模块。我正在使用此模块使用其check_output函数在远程设备上运行命令。可能存在远程设备无法运行的情况,因此我收到以下响应: Timeout: No Response from 10.xxx.xxx.xxx 以下是我的代码:

try:
    x=subprocess.check_output(command, shell=True)
except Exception:
    print ("Some issues in fetching details")
    exit()
else:
    print (x)

我想将超时置于此函数中,以便在一定时间后没有收到响应,我的代码进入Exception部分并打印给定的消息。我尝试在check_output命令中使用timeout参数,但在使用timeout参数运行脚本后,它会立即打印Exception部分中给出的消息。 我尝试了什么:

try:
    x=subprocess.check_output(command, shell=True, timeout=5)
except Exception:
    print ("Some issues in fetching details")
    exit()
else:
    print (x)

2 个答案:

答案 0 :(得分:3)

我的猜测是你在Python 2中运行你的代码。

如果是这种情况,subprocess.check_output()不接受timeout参数,该函数将立即失败:

TypeError: __init__() got an unexpected keyword argument 'timeout'

但是,因为您正在捕获所有异常并打印通用消息,所以您没有看到实际异常,并且您认为命令会立即超时。

解决此问题的一种方法是在Python 3中运行代码。

无论您是运行Python 2还是3,我建议您不要捕获所有异常,或者至少打印异常值以便您可以看到实际原因,例如

try:
    x=subprocess.check_output(command, shell=True, timeout=5)
except subprocess.TimeoutExpired as exc:
    print("Command timed out: {}".format(exc))
    exit()
else:
    print (x)

显式检查超时异常。所有其他异常都照常传播,因此不会被“全部捕获”代码掩盖。或者,

try:
    x=subprocess.check_output(command, shell=True, timeout=5)
except Exception as exc:
    print("Command failed: {}".format(exc))
    exit()
else:
    print (x)

但前者是首选。

修改

OP无法使用Python 3.如果您使用的是Linux,则可以使用timeout命令,例如

x = subprocess.check_output('timeout 5 {}'.format(command), shell=True)

在超时时,这将引发具有特定退出状态值124的异常:

subprocess.CalledProcessError: Command 'timeout 5 sleep 10' returned non-zero exit status 124

顺便说一下,您不应该使用shell=True选项,因为文档中提到了安全隐患。相反,您应该将字符串列表传递给check_output(),如下所示:

from shlex import shlex

command = shlex('timeout 5 {}'.format(command))
try:
    x = subprocess.check_output(command)
except subprocess.CalledProcessError as exc:
    if exc.returncode == 124:
        print "Command timed out"
    else:
        raise

如果您正在使用其他操作系统(或者您不想使用timeout),则可以在单独的线程中运行子进程,并在需要时让主线程将其计时。有关如何执行此操作的详细信息,请参阅另一个问题Using module 'subprocess' with timeout

答案 1 :(得分:2)

Python 2.7不支持timeout参数。您可以使用EasyProcess。这是一个位于子进程模块之上的层,非常易于使用。