【问题标题】:subprocess.Popen stdout and stderr value mismatchsubprocess.Popen 标准输出和标准错误值不匹配
【发布时间】:2021-09-03 19:49:24
【问题描述】:

我正在尝试使用 Python3 subprocess 模块的 Popen 命令来编写脚本。我正在尝试获取几个已安装软件的版本,如下所示。

from subprocess import Popen, PIPE
nginx_version, err = Popen(["nginx", "-v"], stdout=PIPE, stderr=PIPE).communicate()
print("Nginx Version:" + nginx_version.decode("utf-8"))
print("Stderr:" + err.decode("utf-8"))
###################OUTPUT####################
Nginx Version:
Stderr: nginx version: nginx/1.16.1

有没有办法以标准方式转换和处理 STDOUT 和 STDERR?

【问题讨论】:

  • 你有什么理由相信这不是正确的输出,nginx 将其版本号写入标准错误?最明显的解释是 Python 正在做它应该做的事情,而 Nginx 是唯一表现出令人惊讶的组件。
  • 例如:在bash命令行上,你从nginx --version 2>/dev/null得到什么?如果它是空的,你就知道 stderr 确实是 nginx 正在写入的地方。
  • @CharlesDuffy 这种行为真的很奇怪。 nginx -v 1> /dev/null 正在打印版本 nginx version: nginx/1.16.1nginx -v 2> /dev/null 没有打印任何内容
  • 这并不奇怪。它只是告诉您版本被写入标准错误而不是标准输出。这可以说是一个错误,因为版本号是 --version 入口点的预期输出,但它与您的 Python 代码正在执行的操作完全一致。如果您希望在 nginx 的未来版本中更正它,我建议与其维护者交谈。

标签: python shell subprocess popen stdio


【解决方案1】:

这种行为看起来很奇怪,文档明确说明

communicate() 返回一个元组 (stdout_data, stderr_data)。如果流以文本模式打开,则数据将是字符串;否则,字节。

我会按以下方式设置它,注意使用text=True 以避免解码字节输出。

from subprocess import Popen, PIPE

def get_version(name):
    proc = Popen([name, "--version"], stdout=PIPE, stderr=PIPE, text=True)
    program_version, stderr = proc.communicate()
    exitcode = proc.returncode
    return program_version.strip(), stderr.strip(), exitcode

nginx_version, stderr, exit_code = get_version("nginx")

if exit_code == 0:
    print("Nginx Version: " + nginx_version)
else:
    print("Stderr: " + stderr)

运行上面的代码时会不会出现同样的不匹配?

【讨论】:

  • 为什么这会改变 OP 所展示的行为?