Python subprocess.popen:重定向`s stderr`仅保留``stdout''

发布于 2025-02-14 01:09:04 字数 2582 浏览 1 评论 0原文

设置

我有一个小Runner程序,该程序在sys.stderr中打印一些信息(对于日志,未手动异常等)和sys.ss.stdout(有关程序的一些有用信息,可能与用户或SMTH互动):

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程序,在新窗口 Runner >与subprocess.popen并打印其输出:

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')}]")

因此,结果输出是:

[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

我需要运行几个跑步者最近等待它们,但是subprocess.check_inputsubprocess.run不允许(或者我错了) ??)

为什么要新窗口?

我想在他们的个人窗口中分别查看每个runner

我想要

重定向stderr 唯一的,并保留stdout < /code>在打开的窗口中,因此main程序只会从子过程中输出错误:

[This is text #1 to STDERR
This is text #2 to STDERR
This is text #3 to STDERR
]

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

我尝试了什么

什么时候subprocess.popen has stderr = subprocess.pipe param and stdout = none(默认),stdout是阻止:

  • 它没有在Runner窗口
  • proc.communate返回

中显示,因此stdout打印只是消失了...我什至尝试通过sys.stdout to stdout = param(用于窗口中的输出,而是在当前控制台中),但是它抛出了不良文件描述符错误:

[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 )成功地重定向

的。

Setup

I have a little Runner program, that prints some info in sys.stderr (for logs, unhandled exceptions and etc.) and sys.stdout (some usefull info about program, maybe interaction with user or smth):

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)

And I have some Main program, that starts Runner in the new window with subprocess.Popen and prints it's output:

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')}]")

So the resulting output is:

[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
]
Why Popen?

I need to run several Runners parallely and wait them lately, but subprocess.check_input or subprocess.run does not allow that (or am I wrong??)

Why new window?

I want to see prints separetely for every Runner in their personal windows

What I want

I want to redirect stderr only and keep stdout in opened window, so the Main program will only output errors from subprocess:

[This is text #1 to STDERR
This is text #2 to STDERR
This is text #3 to STDERR
]

That will be very usefull for debugging new Runner's features...

What I tried

When subprocess.Popen has stderr=subprocess.PIPE param and stdout=None (default), stdout is blocking:

  • it doesn't show in the Runner window
  • and proc.communicate returns None

So the stdout prints just disappeared... I tried even pass sys.stdout to stdout= param (for output not in window, but in current console), but it throws Bad file descriptor error:

[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
]

(btw, this print was succesfully redirected from Runner to Main)

Need help...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝梦月影 2025-02-21 01:09:04

这是一个满足“我想要的”部分要求的解决方案:

main.py

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.py包含代码问题。

参数shell = false用于直接运行python runner.py(即不作为shell命令),text = true make> make subprocess open process.stderr在文本模式下(而不是二进制模式)。

运行此操作时,从runner.py发送到 stdout 的输出出现在新窗口中,而输出发送到 stderr 则在变量中捕获到 stderr stderr(也印在main.py的窗口中)。


如果runner.py的输出应在生产时立即处理(即不等待该过程首先完成),则可以使用以下代码:

main.py.py :

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(修改以说明差异):

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 's stderr


在Windows 10 21H2 + Python 3.10.4上成功测试。

Here is a solution that meets the requirements of the 'What I want' section:

main.py:

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 contains the code mentioned in the question.

Argument shell=False is used to run python runner.py directly (i.e. not as a shell command), text=True makes subprocess open process.stderr in text mode (instead of binary mode).

When running this, output from runner.py sent to stdout appears in the new window while output sent to stderr is captured in variable stderr (and also printed in main.py's window).


If runner.py's output shall be processed right away as it is produced (i.e. without waiting for the process to finish first), the following code may be used:

main.py:

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 (modified to illustrate the difference):

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)

Argument bufsize=1 is used here to get line-buffered output from runner.py's stderr.


Successfully tested on Windows 10 21H2 + Python 3.10.4.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文