【问题标题】:Python - Using Popen.communicate() does not capture the stdout and stderr of a system call as expectedPython - 使用 Popen.communicate() 不会按预期捕获系统调用的标准输出和标准错误
【发布时间】:2014-03-18 15:01:02
【问题描述】:

我有一个执行系统调用的 Python 脚本(调用实际上是一个java 程序)。 我正在使用Popen.communicate()尝试 捕获stdoutstderr。但是,它仅适用于某些Java 应用程序(其中,我调用的所有java 应用程序在直接在shell 中执行时都会在屏幕上显示一些内容)。

我使用的代码如下:

    # Perform the java call
    try:

        p = subprocess.Popen(args,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)

    except OSError as e:
        error_msg = '  Error reading file while executing system command: {0}'.format(e.message)

    except ValueError as e:
        error_msg = '  Error in arugments while executing system command: {0}'.format(e.message)

    else:
        # Display the results in real time
        for line in iter(p.stdout.readline, ''):
            sys.stdout.write(line)

        # Grab the stdout and stderr from the process.
        output, err = p.communicate()

    finally:
        # Check to see if an internal error occurred. If not, flip the flag
        if not err and not error_msg:
            java_completed = True
        else:
            java_completed = False

在某些情况下,sys.stdout.write(line) 行永远不会被调用,而在其他情况下却是。

有人有这方面的经验吗?

【问题讨论】:

    标签: python subprocess


    【解决方案1】:

    我注意到的第一件事是您正在从进程标准输出中读取所有内容,然后尝试执行communicate:您已经从管道中读取了所有内容,因此output 结果来自p.communicate()永远是空的。

    但这并不能解释为什么有时sys.stdout.write 没有被调用。

    要记住的一点是,有多种方式可以在控制台(即命令窗口)中显示内容。打印到进程标准输出流只是一种方式,这就是您可以使用上述代码捕获的方式。如果我记得 Java 时代,有某种类型的 Console 类有时用于显示到控制台,这可能不使用标准输出。此外,高级控制台显示库,例如curses,通常不写入标准输出,它们直接与控制台对象交互。我不知道如何或是否可以从这些类型的进程中捕获输出,但如果可能的话,它可能是非常特定于系统的。

    【讨论】:

    • 感谢您的指点。我认为我没有注意到output 是空的原因是我真的只对stderr 感到好奇。但你确实帮助我了解了它的工作原理。不幸的是,关于如何从Console 类中获取输出的问题仍然悬而未决。
    • +1。 @Brett:另一个问题是您设置了stderr=PIPE,但您没有与stdout 同时读取它。如果程序填满子进程的stderr对应的OS管道缓冲区,可能会导致死锁
    • @J.F.Sebastian 有趣。关于我应该如何处理这个问题的任何指示?
    • @Brett:你可以试试pexpectpty 模块,例如Capture “Segmentation fault” message for a crashed subprocess: no out and err after a call to communicate()(如果程序直接写入终端,它会解决问题)。
    • @Brett:如果您的意思是如何同时读取stdoutstderr,那么 1. 设置stderr=STDOUT 如果不可接受,则 2. 使用线程,或 select.select,或 fctnl (使管道不阻塞)或 iocp(在 Windows 上)
    猜你喜欢
    • 1970-01-01
    • 2018-11-25
    • 2013-05-11
    • 2011-04-17
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    • 2018-08-10
    相关资源
    最近更新 更多