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

标签 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',)))",),)

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

测试.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())

虽然我可以在运行 test.py 时“看到”cmd.exe 上的完整消息, 但记录器仅捕获如下所示...

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 上检查了很多答案。似乎与我的问题非常接近,但没有财富。任何建议都会对我非常有帮助。预先感谢您。

最佳答案

这很可能是因为您只将标准输出重定向到管道。您还必须重定向 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 上您需要运行一个额外的线程,以便可以同时从两个管道中读取数据。

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

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

另一个不需要线程的解决方案可能是将命令的 stderr 重定向到 stdout,然后再将其通过管道传输到 python 进程。您将无法分辨哪些字节最初发送到 stdout,哪些字节发送到 stderr,但根据您的用例,了解这一点可能并不重要。

关于python - 从 stdout 或 stderr 获取子进程的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46157754/

相关文章:

python - 如果错误,执行此操作并返回,否则继续在一行中执行

python - 如何根据文件中的一个占位符写入字典键和值

python - 子进程调用

python - python3中的互斥锁

python - 包含散点图的抛物线方程

python - 调用写入服务器上文件的 url(免费)

python - 从 Python 提示符运行 Python 脚本,以便将变量加载到交互式环境中

python - 在函数中定义字典时Python中的内存泄漏

python - 如何使子进程按顺序获取标准输出和标准错误?

Python 子进程在 Windows 上删除 reg key