如何使用Python捕获subprocess.call错误?

7
我将尝试下载指定的Docker镜像,用户将输入一个版本号。但是,如果该版本不存在,Docker会报错。
我正在使用subprocess.call从Python 3中的终端进行管道传输。
示例代码:
from subprocess import call
containerName = input("Enter Docker container name: ")
swVersion = input("Enter software version: ")

call(["docker", "run", "--name", "{}".format(containerName), 
      "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)])

如果版本未找到,Docker将在终端输出:
docker: Error response from daemon: manifest for user/software:8712378 not found.

如何在Python脚本中捕获此错误?

可以采用以下方法:

try:
    call(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)])
except:
    # How do I catch the piped response code here?`

你是说当它失败时要错误消息吗? 此外,为了格式化代码块,请在行前加上4个空格而不是使用反引号。 - Eric Renouf
好的,我想捕获错误,这样我就可以重新提示用户输入有效的版本,如果这有意义的话 :) - cbll
1
这取决于“捕获错误”的含义,如果你只想在程序出错时引发异常,请使用check_call而不是call;如果你想获取写入到stderr的字符串,则应该以另一种方式实现。 - Eric Renouf
我还没有看过check_call,会去了解一下。通过捕获错误,我指的是向用户打印一个错误消息,并重新提示输入有效的软件编号。错误消息是手工制作的字符串。 - cbll
1
问题仍然存在,你是否想要获取调用程序写入到 stderr 的字符串? - Eric Renouf
如果我理解你的意思正确的话,那么不,我只是想在Python脚本中捕获它,而不是在Bash中? :) 看起来我可以用check_call来捕获任何错误,谢谢 - 至少有东西可以处理了! - cbll
3个回答

12
如果你不介意程序将其输出写入stderr并且你不直接与它交互,那么实现你所要求的最简单方法是使用check_call而不是callcheck_call在运行的命令以除0以外的任何状态退出时会引发异常。
try:
    check_call(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)])
except CalledProcessError:
    print("That command didn't work, try again")

8
您可以使用subprocessPopen函数在Python控制台中抓取stderr并打印,正如文档中对subprocess.call所说的那样。

请注意,不要在此功能中使用stdout=PIPE或stderr=PIPE,因为这可能会根据子进程输出量导致死锁。当您需要管道时,请使用Popen与communicate()方法。

proc = subprocess.Popen(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)],stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess_flags)
proc.wait()
(stdout, stderr) = proc.communicate()

if proc.returncode != 0:
    print(stderr)
else:
    print("success")

1
上面的答案检查返回代码是可行的,但更Pythonic的方法是捕获异常,例如:
try:
    proc = subprocess.Popen(["docker", "run", "--name", "{}".format(containerName), "--detach", "--publish", "8080:8080", "user/software:{}".format(swVersion)],stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess_flags)
    proc.wait()
    (stdout, stderr) = proc.communicate()

except calledProcessError as err:
    print("Error ocurred: " + err.stderr)

calledProcessError 是 Popen 类捕获的错误。

如果您想捕获操作系统或系统级别上的常见错误(例如文件/目录不存在),请添加以下异常:

except OSError as e:
    print ("OSError > ",e.errno)
    print ("OSError > ",e.strerror)
    print ("OSError > ",e.filename)

except:
    print ("Error > ",sys.exc_info()[0])

如果您想返回一个返回码,应明确地这样做,而不是使用print()函数。在最后一个except语句之后编写,并与try语句处于相同的缩进级别:

return True

如果您想返回一条消息,可以使用Response对象:
return Response ("Success Message")

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