在 subprocess.check_output 中添加超时

Adding timeout in subprocess.check_output

我正在 Python 2.7 中开发一个小工具并使用 subprocess 模块。我正在使用此模块使用其 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 命令中使用超时参数,但在 运行 将我的脚本与超时参数连接后,它会立即打印异常部分中给出的消息。 我尝试了什么:

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

我的猜测是您 运行 在 Python 2.

中使用您的代码

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

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

但是,因为您正在捕获 所有 异常并打印一般消息,所以您没有看到实际的异常,并且您假设命令立即超时。

解决此问题的一种方法是 运行 您在 Python 3.

中的代码

不管你是运行ning Python2还是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)

它显式检查超时异常。所有其他异常都照常传播,因此不会被您的 "catch all" 代码屏蔽。或者,

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

如果你正在使用另一个OS(或者你不想使用timeout)那么你可以运行你的子进程在一个单独的线程中并且有你的主线程时间如果需要的话。请参阅另一个问题 Using module 'subprocess' with timeout,了解有关如何执行此操作的详细信息。

Python 2.7 不支持超时参数。您可以改为使用 EasyProcess。这是子流程模块之上的一层,非常易于使用。