Python - 使用Popen.communicate()无法按预期捕获系统调用的stdout和stderr

2 投票
1 回答
1597 浏览
提问于 2025-04-17 22:49

我有一个Python脚本,它会执行一个系统调用(这个调用实际上是一个java程序)。我正在使用Popen.communicate()尝试捕获stdout(标准输出)和stderr(错误输出)。不过,这个方法只对某些Java应用程序有效(我调用的所有java应用程序在直接在命令行中执行时,都会在屏幕上显示一些内容)。

我使用的代码如下:

    # 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)这一行从来没有被调用,而在其他情况下又会被调用。

有没有人有过类似的经验?

1 个回答

1

我首先注意到的是,你在从进程的标准输出(stdout)中读取所有内容,然后再尝试使用communicate:你已经从管道中读取了所有内容,所以p.communicate()output结果总是会是空的。

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

需要记住的一点是,在控制台(也就是命令窗口)中显示内容有很多种方式。打印到进程的标准输出流只是其中一种,而这也是你能用上面代码捕获到的方式。如果我没记错的话,在Java中有一种Console类,有时用来在控制台上显示内容,这可能并不使用标准输出。此外,一些高级的控制台显示库,比如curses,通常不会写入标准输出,而是直接与控制台对象进行交互。我不知道你是否能捕获这些类型进程的输出,但如果可以的话,可能会非常依赖于具体的系统。

撰写回答