Python-使用Popen.communicate()不会像预期的那样捕获系统调用的stdout和stderr

Python-使用Popen.communicate()不会像预期的那样捕获系统调用的stdout和stderr,python,subprocess,Python,Subprocess,我有一个Python脚本,它执行一个系统调用(该调用实际上是一个java程序)。 我正在使用Popen.communicate()尝试捕获stdout和stderr。但是,它只适用于一些Java应用程序(其中,我调用的所有Java应用程序在shell中直接执行时都会在屏幕上显示一些内容) 我使用的代码如下: # Perform the java call try: p = subprocess.Popen(args,

我有一个Python脚本,它执行一个系统调用(该调用实际上是一个
java
程序)。 我正在使用
Popen.communicate()
尝试捕获
stdout
stderr
。但是,它只适用于一些
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)
,而在另一种情况下则是这样


有人对此有任何经验吗?

我注意到的第一件事是,您正在读取进程stdout中的所有内容,然后尝试执行
通信
:您已经读取了管道中的所有内容,因此
输出
结果来自
p.communicate()
将始终为空

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


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

感谢您的指点。我想我没有注意到
输出
为空的原因是我真的只对
stderr
感兴趣。但你确实帮我了解了一些这是怎么回事。不幸的是,关于如何从
控制台
类获取输出的问题仍然悬而未决@布雷特:另一个问题是,您设置了
stderr=PIPE
,但没有与
stdout
同时读取。如果程序填充对应于子进程的操作系统管道缓冲区,则可能导致死锁stderr@J.F.Sebastian有趣。关于我应该如何处理这个问题,有什么建议吗?@Brett:你可以尝试
pexpect
pty
模块,例如,(如果程序直接写入终端,它会解决问题)。@Brett:如果你指的是如何同时读取
stdout
stderr
,那么1。设置
stderr=STDOUT
如果不可接受,则设置2。使用threads、select.select、fctnl(使管道不阻塞)或iocp(在Windows上)