从stdout或stderr获取子进程的消息

时间:2017-09-11 14:10:32

标签: python python-3.x subprocess

我暂时改变了我的代理配置,以便在cmd.exe上产生以下错误...

C:\Users\su79e\abs_engine>C:/ProgramData/Anaconda3/Scripts/conda create --name test python=3.5

Fetching package metadata ...

# After 5~10 seconds

CondaHTTPError: HTTP None None for url <https://repo.continuum.io/pkgs/free/win-64/repodata.json.bz2>
Elapsed: None

An HTTP error occurred when trying to retrieve this URL.
HTTP errors are often intermittent, and a simple retry will get you on your way.
ProxyError(MaxRetryError("HTTPSConnectionPool(host='repo.continuum.io', port=443): Max retries exceeded with url: /pkgs/free/win-64/repodata.json.bz2 (Caused by ProxyError('Cannot connect to proxy.', NewConnectionError('<requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x000001DBCA650AC8>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed',)))",),)

那很好。另一方面,我想使用子进程模块捕获这些错误消息,如下面的代码。

test.py

with subprocess.Popen("C:/ProgramData/Anaconda3/Scripts/conda create -y --name test python=3.5",
                      universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc:
    # out, err = proc.communicate()
    # logger.info(out)
    # logger.info(err)
    while proc.poll() is None:
        logger.info(proc.stdout.readline())
        # logger.info(proc.stderr.readline())

虽然我可以&#34;看到&#34;运行cmd.exetest.py上的完整消息, 但记录器只捕获如下...

test.py:104 - INFO - 2017-09-11 22:16:29,858 - Fetching package metadata ...
test.py:104 - INFO - 2017-09-11 22:16:29,858 - 

尽管有while循环,它只会在错误之前捕获消息。我错过了什么吗?我已经在Stackoverflow上检查了很多答案,this似乎与我的问题非常接近,但没有财富。任何建议对我都非常有帮助。提前谢谢。

1 个答案:

答案 0 :(得分:2)

最有可能的原因是你只将stdout重定向到管道。您还必须重定向stderr(请参阅Popen的文档):

subprocess.Popen("C:/ProgramData/Anaconda3/Scripts/conda create -y --
name test python=3.5", universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE) as proc:

(你在这里错过了stderr=subprocess.PIPE

但是如果你将stdout和stderr重定向到一个管道,那么在windows上你需要运行一个额外的线程,这样你就可以同时读取这两个管道。

如果你在单个线程中执行它并在读取stdout时阻塞大量数据被转储到stderr管道,你可能会永远挂起,因为stderr管道缓冲区会填满并阻塞写入stderr的进程,意味着两个进程都会死锁,一个等待stderr缓冲区变为空,另一个进程则stdout缓冲区填满一行输出。

在Linux上,您可以使用select调用来选择具有可读取数据的管道,但这仅适用于Windows上的套接字。

另一个不需要线程的解决方案可能是将命令的stderr重定向到stdout,然后再将它传递给你的python进程。您将无法分辨哪些字节最初转到stdout以及哪些字节转到stderr,但根据您的使用情况,这可能并不重要。