首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Python subprocess.Popen:只重定向“`STDERR`”并保留“`STDOUT`”

Python subprocess.Popen:只重定向“`STDERR`”并保留“`STDOUT`”
EN

Stack Overflow用户
提问于 2022-07-08 14:37:13
回答 1查看 206关注 0票数 1

设置

我有一个小的Runner程序,它在sys.stderr中打印一些信息(对于日志、未处理的异常等等)。和sys.stdout (一些有用的程序信息,可能是与用户或smth的交互):

代码语言:javascript
运行
复制
import sys
import time

for i in range(1, 4):
    sys.stdout.write(f"This is text #{i} to STDOUT\n")
    sys.stderr.write(f"This is text #{i} to STDERR\n")

time.sleep(5)

我有一些Main程序,它在新窗口中用subprocess.Popen启动Runner并打印它的输出:

代码语言:javascript
运行
复制
import subprocess

cmd = "python runner.py"
proc = subprocess.Popen(cmd,
                        stdout=subprocess.PIPE, # Problem line
                        stderr=subprocess.PIPE,
                        creationflags=subprocess.CREATE_NEW_CONSOLE
                       )

proc.wait()
out, err = proc.communicate()
if out:
    print(f"[{out.decode('utf-8')}]")
if err:
    print(f"[{err.decode('utf-8')}]")

因此,产生的输出是:

代码语言:javascript
运行
复制
[This is text #1 to STDOUT
This is text #2 to STDOUT 
This is text #3 to STDOUT
]
[This is text #1 to STDERR
This is text #2 to STDERR
This is text #3 to STDERR
]

为什么Popen

我需要并行运行几个Runners,并等待它们最近,但是subprocess.check_inputsubprocess.run不允许这样做(或者我错了吗?)

为什么是新窗户?

我想要为他们的个人窗口中的每一个Runner单独看到指纹。

我想要的

我希望重定向stderr only ,并将stdout保持在打开的窗口中,因此Main程序只会从子进程输出错误:

代码语言:javascript
运行
复制
[This is text #1 to STDERR
This is text #2 to STDERR
This is text #3 to STDERR
]

这对于调试新的Runner功能非常有用.

我试过的

subprocess.Popen具有stderr=subprocess.PIPE param和stdout=None (默认)时,stdout阻塞:

没有显示在None窗口中的

  • proc.communicate返回Runner

所以stdout指纹就消失了..。我甚至尝试将sys.stdout传递给stdout= param (输出不是在窗口中,而是在当前控制台中),但是它会引发Bad file descriptor错误:

代码语言:javascript
运行
复制
[Traceback (most recent call last):
  File "C:\Users\kirin\source\repos\python_tests\runner.py", line 5, in <module>
    sys.stdout.write(f"This is text #{i} to STDOUT\n")
OSError: [Errno 9] Bad file descriptor
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp1251'>
OSError: [Errno 9] Bad file descriptor
]

(顺便说一句,此打印成功地从Runner重定向到Main__)

需要帮助..。

EN

Stack Overflow用户

发布于 2022-08-04 09:54:24

这里是一个满足‘我想要什么’部分的要求的解决方案:

main.py

代码语言:javascript
运行
复制
import subprocess

command = ["python", "runner.py"]
process = subprocess.Popen(command, shell=False, text=True, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NEW_CONSOLE)
process.wait()
stderr = process.stderr.read()
print(stderr, end="")

runner.py包含问题中提到的代码。

参数shell=False用于直接运行python runner.py (即不作为shell命令),text=True使subprocess在文本模式(而不是二进制模式)中打开process.stderr

运行此操作时,发送给stdout的runner.py的输出将出现在新窗口中,而发送给stderr的输出将在变量stderr中捕获(并且还会打印在main.py的窗口中)。

如果runner.py的输出应在生成时立即处理(即无需等待进程完成),则可以使用以下代码:

main.py

代码语言:javascript
运行
复制
import subprocess

command = ["python", "runner.py"]
process = subprocess.Popen(command, shell=False, text=True, bufsize=1, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NEW_CONSOLE)
stderr = ""
while (True):
    line = process.stderr.readline()
    if (line == ""): break # EOF
    stderr += line
    print(line, end="")

runner.py (修改以说明差异):

代码语言:javascript
运行
复制
import sys
import time

for i in range(1, 4):
    sys.stdout.write(f"This is text #{i} to STDOUT\n")
    sys.stderr.write(f"This is text #{i} to STDERR\n")
    time.sleep(1)

参数bufsize=1用于从runner.py的stderr获得行缓冲输出。

在Windows 1021H2+Python3.10.4上成功测试。

票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72913044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档