【问题标题】:redirecting current runing python process' stdout重定向当前正在运行的 python 进程的标准输出
【发布时间】:2021-08-09 17:21:15
【问题描述】:

我有运行 C 代码的 python 代码,该代码向 stdout 和 stderr 发送垃圾邮件。

我想抑制标准输出和标准错误,但不能修改 C 代码。作为伪代码,大致如下:

def external_api_I_cant_control():
    C code that outputs to stdout & stderr # this is not a subprocess 
                                           # call which I can redirect
                                           # its stdout & stderr. Rather,
                                           # it's a wrapper for it so there
                                           # is nothing I can do to control its
                                           # FD

def do_stuff():
    external_api_I_cant_control()

我的代码正在使用python bla.py 运行,因此我可以使用python bla.py 2>/dev/null 重定向stderr,但这并不能解决我的问题,因为一些垃圾邮件是stdout,我无法重定向stdout - 因为我需要一些。

是否可以在我的代码中执行相当于 shell 标准输出重定向的操作?

到目前为止我试过了:

  1. contextlib.redirect_stdout
  2. 将sys.stdout 和sys.__stdout__ 替换为open(os.devnull, 'w')

我想要的结果相当于将我的 bla.py 拆分为 3 并像这样运行它:

python bla0.output.is.legit.py
python bla1.output.should.be.disregarded.py &> /dev/null
python bla2.output.is.legit.again.py

实现这一目标的方法是什么?

【问题讨论】:

  • os.dup2() 是你的朋友。编写一个使用它的 contextlib.redirect_stdout 的等价物应该不难。
  • 你是如何运行子进程的?你在用subprocess module吗?
  • (说 "subprocess call I can't control",带有 subprocess 代码格式,暗示这是一个 Python subprocess 库使用,而不仅仅是一个由C代码fork()ing和exec()ing创建的实际子进程。如果你是指后者,请不要对其进行代码格式化以避免错误的含义)
  • 只说“子进程”,而不是“subprocess”。当你说 subprocess 时,这意味着 subprocess 是代码,而作为 Python 代码,这意味着使用标准库 subprocess 模块。
  • 您可以使用dup2() 将文件描述符复制到另一个已经存在的FD——这样您就可以复制新的/不同的内容over stdout 或 stderr 来替换它。这就是重定向在 C 中的工作方式(以及 shell 如何在后台实现它)。

标签: python stdout io-redirection


【解决方案1】:

这是os.dup2() 的工作。您想要的代码包含三个阶段:

  • 备份原始标准输出和标准错误
  • 用指向/dev/null的文件句柄替换stdout和stderr
  • 正在恢复备份(在运行所需的代码之后)。

# create a backup of stdout and stderr
orig_stdout_fd = os.dup(1)
orig_stderr_fd = os.dup(2)

# make the original stdout and stderr point to /dev/null
devnull = open('/dev/null', 'r+')
os.dup2(devnull.fileno(), 1)
os.dup2(devnull.fileno(), 2)

# run your C code here
os.write(1, b"This would normally go to stdout\n")

# put the originals back
os.dup2(orig_stdout_fd, 1)
os.dup2(orig_stderr_fd, 2)
os.close(orig_stdout_fd)
os.close(orig_stderr_fd)

【讨论】:

  • 效果很好。谢谢!对我来说这似乎很奇怪contextlib 没有这样做
  • 还有,为什么最后关闭了原来的FD?
  • @CIsForCookies,文件描述符是有限的资源。诚然,在现代操作系统上可用的数量并不是那么少,但这并不是编写泄露它们的代码的借口;循环调用它,最终会用完。
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 2011-01-06
  • 1970-01-01
  • 2013-06-02
  • 2017-07-22
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多