【问题标题】:Getting messages of subprocess from stdout or stderr从 stdout 或 stderr 获取子进程的消息
【发布时间】:2017-09-11 14:10:31
【问题描述】:

我暂时更改了我的代理配置以在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 模块来捕获这些错误消息,如下面的代码。

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())

虽然我可以在运行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 似乎与我的问题非常接近,但没有运气。任何建议都会对我很有帮助。提前谢谢你。

【问题讨论】:

    标签: python python-3.x subprocess


    【解决方案1】:

    这很可能是因为您只将标准输出重定向到管道。您还必须重定向 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,但根据您的用例,知道这可能并不重要。

    【讨论】:

      猜你喜欢
      • 2013-08-26
      • 2012-03-16
      • 2014-10-14
      • 2020-06-23
      • 1970-01-01
      • 2023-04-06
      • 2011-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多