在subprocess.check_output中添加超时时间

3

我正在使用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)

我想在这个函数中设置超时时间,以便如果在一定时间内没有收到响应,我的代码将进入异常部分并打印给定的消息。我尝试在check_output命令中使用timeout参数,但在使用timeout参数运行脚本后,它立即打印了异常部分中给定的消息。

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

你正在使用Python 2还是3? - mhawke
2个回答

4

我猜测你在运行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)

但是更推荐前者。

编辑

如果您使用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),那么您可以在单独的线程中运行子进程,并在必要时让主线程超时。请参阅另一个问题,如何使用'module subprocess'设置超时,了解如何实现。


@Vipul:是的,你的代码立即转到异常处理程序的原因在答案中已经解释了,即Python 2不支持check_output()的超时选项。你不知道这一点是因为你的异常处理程序没有打印实际的异常,所以你不知道你的代码为什么会失败。好的,如果你不能使用Python 3,那么你使用的操作系统是什么? - mhawke
@Vipul:在答案中添加了一些替代方案。 - mhawke
在执行您所述的操作时,代码立即打印“命令超时”。它不应该尝试5秒钟然后给出超时错误消息吗? - Vipul
你有一个语法错误。请修改并重试。我看到可能会有一些漂浮的反引号(''`),但我不知道它们是在回溯中还是你加入了它们进行格式化。除此之外,代码看起来没问题。 - mhawke
确切地说,没有任何多余的东西,我已经尝试了很多次,我不明白为什么它会显示那样。 - Vipul
显示剩余9条评论

2

Python 2.7不支持timeout参数。您可以使用EasyProcess代替。这是在subprocess模块之上的一层,并且非常容易使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接