我想在python脚本中隐藏stdout / stderr 但是当python模块需要打印时,打印不会进入python脚本本身,而是放在底层的.c扩展名中。
是 netsnmp python模块的情况,它需要编译,问题是有一些'printf'直接进入我想捕获的C(client_intf.c)代码中隐藏:
from netsnmp import *
import sys,os
devnull = open(os.devnull, 'w')
sys.stdout, sys.stderr = devnull, devnull
session = Session(DestHost='myhostthatdoesnotexisttogenerateerror',Version=2,Community='demopublic')
当我运行它时,我仍然有一些痕迹:
python test.py
getaddrinfo: myhostthatdoesnotexisttogenerateerror nodename nor servname provided, or not known
error:snmp_new_session: Couldn't open SNMP session
如何在stdout / stderr上删除这些消息?这很重要,因为我正在开发Nagios插件,我可以负担得起这样的输出(尽管如此,我想捕获它们以引发自定义异常)
答案 0 :(得分:1)
Eric 的回答非常好,但它有一个重要的缺点:如果您已经使用 sys.stderr
来初始化某些东西,它将变得毫无用处。例如:如果您使用 sys.stderr
创建自定义错误记录器,它将停止工作。
这是修改后的版本:
import os
from contextlib import contextmanager
@contextmanager
def hide_stderr():
""" Low level stderr supression. """
newstderr = os.dup(2)
devnull = os.open('/dev/null', os.O_WRONLY)
os.dup2(devnull, 2)
os.close(devnull)
yield
os.dup2(newstderr, 2)
@contextmanager
def hide_stdout():
""" Low level stdout supression. """
newstderr = os.dup(1)
devnull = os.open('/dev/null', os.O_WRONLY)
os.dup2(devnull, 1)
os.close(devnull)
yield
os.dup2(newstderr, 1)
import sys
my_stderr = sys.stderr
print("Test 1: no stderr, no stdout")
with hide_stderr():
with hide_stdout():
print("1 stdout")
print("2 stderr", file=my_stderr)
print("Test 2: no stderr, but stdout")
with hide_stderr():
print("1 stdout")
print("2 stderr", file=my_stderr)
print("Test 3: stderr, no stdout")
with hide_stdout():
print("1 stdout")
print("2 stderr", file=my_stderr)
print("Test 4: stderr and stdout")
print("1 stdout")
print("2 stderr", file=my_stderr)
请注意,主要区别在于末尾使用了 os.dup2
。我们从我们所做的副本中恢复了文件描述符,我们不会弄乱 sys.stderr
。
答案 1 :(得分:0)
根据您的操作系统(似乎至少在Windows和Linux上都有效),以下内容将通过替换(低级别)文件描述符完全关闭fx stdout
:
nulf = os.open(os.devnull, os.O_WRONLY)
os.dup2(nulf, stdout.fileno())
os.close(nulf)
与stderr
相同似乎在交互模式下效果不佳(我猜python解释器试图将它的内容写入stderr)。
此解决方案具有与启动解释器时重定向到/dev/null
或等效的解决方案相同的效果(除非它稍后生效),包括以本机代码生成的任何打印输出(当然,任何打印输出的脚本都是试图做)。如果您要进行任何日志记录,则必须为此打开文件(如果您想将os.devnull
重定向到文件,也可以首先打开stdout
以外的文件)。
请注意,通常程序不检查打印输出的结果,在这种情况下,可以简单地关闭描述符(即os.close(stdout.fileno())
),但如果扩展实际检查结果并且基于不同的行为,则会失败在那。
答案 2 :(得分:0)
这是临时阻止stdout和stderr的代码:
from netsnmp import *
import sys,os
newstdout = os.dup(1)
newstderr = os.dup(2)
devnull = os.open('/dev/null', os.O_WRONLY)
os.dup2(devnull, 1)
os.dup2(devnull, 2)
os.close(devnull)
# stdout/stderr are blocked here
print "I will be back but nobody will know it"
session = Session(DestHost='myhostthatdoesnotexisttogenerateerror',Version=2,Community='demopublic')
sys.stdout = os.fdopen(newstdout, 'w')
sys.stderr = os.fdopen(newstderr, 'w')
# stdout/stderr are unblocked here
print "I'm back"