【问题标题】:how to capture subprocess error如何捕获子进程错误
【发布时间】:2014-03-23 02:07:27
【问题描述】:

在 Python 中,我运行一个使用 FORTRAN 制作的 exe。我使用subprocess 模块。该exe访问并写入多个文件。如果我将这些文件设为只读,我会在我的 Python 控制台中看到以下跟踪。

我尝试使用tryexcept 语句。但我无法捕捉到错误。我也尝试使用p.stdout.readline()。但是没有成功。

是否有系统的方法来捕获此类错误。

代码:

import subprocess
p = subprocess.Popen('C:\\TGSSR\\test.exe' , shell=True, stdout=subprocess.PIPE)

追溯:

forrtl: severe (9): permission to access file denied, unit 6, file C:\test\mar22_SSOUT\RawReadLog.dat

Image              PC        Routine            Line        Source             
test.exe           0116DC40  Unknown               Unknown  Unknown
test.exe           0113D42F  Unknown               Unknown  Unknown
test.exe           0112AE97  Unknown               Unknown  Unknown
test.exe           0112A1DA  Unknown               Unknown  Unknown
test.exe           0110D746  Unknown               Unknown  Unknown
test.exe           0108B9AC  Unknown               Unknown  Unknown
test.exe           01173FE3  Unknown               Unknown  Unknown
test.exe           011588F5  Unknown               Unknown  Unknown
kernel32.dll       76D33677  Unknown               Unknown  Unknown
ntdll.dll          77A39F42  Unknown               Unknown  Unknown
ntdll.dll          77A39F15  Unknown               Unknown  Unknown

【问题讨论】:

标签: python subprocess


【解决方案1】:

运行进程:

p = subprocess.Popen(['C:\\TGSSR\\test.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# shell = True is not needed

要捕获错误消息:

stdout, stderr = p.communicate()
# stdout = normal output
# stderr = error output

查看进程返回码:

if p.returncode != 0:
    # handle error

【讨论】:

  • 虽然在 Windows 上可能不需要,但如果您不打算使用 shell,您应该将可执行文件作为列表传递:['C:\\TGSSR\\test.ext']。此外,返回码可能不可靠,因为(据我所知),在 Fortran 中设置进程的返回码仍然没有一个好的标准化方法。
  • 在这种情况下,p 在两种状态下(成功或不成功)都为空。所以我无法依赖它!
  • @mgilson:Popen("program") 有效。它相当于 POSIX 上的 Popen(["program"])。在 Windows 上,字符串参数始终有效。
  • @user3161836: p 不为空;你可能是指p.returncode is None。后者意味着该过程尚未完成。你应该检查p.returncode 之后 p.communicate()返回(它等待过程完成)
  • @mgilson:我实际上忘记了这一点。感谢您指出这一点。
【解决方案2】:

Python 3.5 引入了subprocess.run() 方法。

这是针对 Python >=3.5 更新的@kirbyfan64sos 答案:

运行进程:

p = subprocess.run(['C:\\TGSSR\\test.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

在 >=3.5 中,您可以从执行的进程中访问returncodestdoutstderr

要捕获错误消息:

stdout = p.stdout # stdout = normal output
stderr = p.stderr # stderr = error output

查看进程返回码:

if p.returncode != 0:
# handle error

【讨论】:

    【解决方案3】:

    如果不需要 Popen 的所有功能而只需要获取标准输出,您也可以选择:

    try:
        output = subprocess.check_output('C:\\TGSSR\\test.exe')
    except subprocess.CalledProcessError as e:
        print("Oops... returncode: " + e.returncode + ", output:\n" + e.output)
    else:
        print("Everything ok:\n" + output)
    

    编辑:正如 mgilson 在另一个答案中指出的那样,这需要失败时的非零返回码。如果不是这种情况,您可以尝试以下方式:

    output = subprocess.check_output('C:\\TGSSR\\test.exe')
    if "permission to access file denied" in output:
        print("Failed")
    

    带有一些仅在出现错误时才会出现在标准输出上的字符串

    【讨论】:

    • 在这种情况下应该是subprocess.CalledProcessError
    • 这对我有用。如果我只需要运行 exe,我想我可以选择这个选项。如果我这样做,我会错过任何主要功能吗?
    • 这可能措辞不好,check_output 是一个基于 Popen 的便利函数,不需要自己处理 stdout/stderr(在你的第一篇文章中,你实际上至少需要一个 p.communicate()如果您的 FORTRAN 工具输出很多会有效地停止执行,以防止 stdout 管道缓冲区完全填充)。但是,您可以轻松切换到 Popen。 Popen 对进程创建提供了更细粒度的控制:link
    猜你喜欢
    • 2021-02-22
    • 1970-01-01
    • 2011-08-04
    • 2019-01-17
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    相关资源
    最近更新 更多