打印大量格式化数据时如何避免Broken Pipe错误?
Posted
技术标签:
【中文标题】打印大量格式化数据时如何避免Broken Pipe错误?【英文标题】:How to avoid a Broken Pipe error when printing a large amount of formatted data? 【发布时间】:2013-04-03 17:18:08 【问题描述】:我正在尝试打印我的stdout
格式的元组列表。为此,我使用str.format 方法。一切正常,但是当我通过管道输出查看
使用head
命令的第一行会出现IOError
。
这是我的代码:
# creating the data
data = []$
for i in range(0, 1000):
pid = 'pid%d' % i
uid = 'uid%d' % i
pname = 'pname%d' % i
data.append( (pid, uid, pname) )
# find max leghed string for each field
pids, uids, pnames = zip(*data)
max_pid = len("%s" % max( pids) )
max_uid = len("%s" % max( uids) )
max_pname = len("%s" % max( pnames) )
# my template for the formatted strings
template = "0:%d\t1:%d\t2:%d" % (max_pid, max_uid, max_pname)
# print the formatted output to stdout
for pid, uid, pname in data:
print template.format(pid, uid, pname)
这是我运行命令后得到的错误:python myscript.py | head
Traceback (most recent call last):
File "lala.py", line 16, in <module>
print template.format(pid, uid, pname)
IOError: [Errno 32] Broken pipe
谁能帮我解决这个问题?
我尝试将print
放入try-except
块中以处理错误,
但之后控制台中出现另一条消息:
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
我还尝试通过两个连续的方法立即刷新数据
sys.stdout.write
和 sys.stdout.flush
打电话,但什么也没发生..
【问题讨论】:
发生这种情况是因为head
关闭 stdout
,导致print
尝试写入已关闭的文件。你希望发生什么?
好的,谢谢!我想避免在控制台中打印此类消息。我想将此代码的变体用于命令行工具。
这个问题可能是重复的;见:***.com/questions/11423225/…
重复:IOError: [Errno 32] Broken pipe when piping: `prog.py | othercmd`
【参考方案1】:
head
从stdout
读取,然后关闭它。这会导致print
失败,它在内部写入sys.stdout
,现在已关闭。
您可以简单地捕捉 IOError
并静默退出:
try:
for pid, uid, pname in data:
print template.format(pid, uid, pname)
except IOError:
# stdout is closed, no point in continuing
# Attempt to close them explicitly to prevent cleanup problems:
try:
sys.stdout.close()
except IOError:
pass
try:
sys.stderr.close()
except IOError:
pass
【讨论】:
好的,在这个简单的程序中可以正常工作,但在命令行工具中有时可以工作,有时会再次出现此消息:close failed in file object destructor: sys.excepthook is missing lost sys.stderr
哈哈!我也在***的一些答案中找到了它!我试过了,但它不起作用!似乎有一个竞争条件..但我不知道如何解决它..
好的,我找到了!它只需要您的答案的补充。只需在打印声明后添加sys.stdout.flush()
!但是错误是您所描述的!我还注意到,出于某种原因,如果我将冲洗排除在循环之外,它也可以工作。无论如何。谢谢你! :)
@ThanasisPetsas:平仓也会受到关闭的影响。
很高兴能帮上忙。 :-) 刷新可能对您有用,因为当使用管道时,python 使用常规文件缓冲区而不是行缓冲区,在这种情况下,刷新有助于逐行获取数据。【参考方案2】:
您看到的行为与 Python3 中的缓冲输出实现相关联。使用 -u 选项或设置环境变量 PYTHONUNBUFFERED=x 可以避免该问题。有关 -u 的更多信息,请参见手册页。
$ python2.7 testprint.py | echo
Exc: <type 'exceptions.IOError'>
$ python3.5 testprint.py | echo
Exc: <class 'BrokenPipeError'>
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
$ python3.5 -u testprint.py | echo
Exc: <class 'BrokenPipeError'>
$ export PYTHONUNBUFFERED=x
$ python3.5 testprint.py | echo
Exc: <class 'BrokenPipeError'>
【讨论】:
是的,但是我在 Python2.7 中遇到了这个问题。我不使用 Python3。【参考方案3】:一般来说,我会尝试找出我能避免的最具体的错误。在这种情况下,它是BrokenPipeError
:
try:
# I usually call a function here that generates all my output:
for pid, uid, pname in data:
print template.format(pid, uid, pname)
except BrokenPipeError as e:
pass # Ignore. Something like head is truncating output.
finally:
sys.stderr.close()
如果这是在执行结束时,我发现我只需要关闭sys.stderr
。如果我不关闭sys.stderr
,我会得到一个 BrokenPipeError 但没有堆栈跟踪。
这似乎是编写输出到管道的工具的最低限度。
【讨论】:
【参考方案4】:在 Python3 中遇到了这个问题,调试日志也通过管道传输到 head 中。如果您的脚本与网络通信或执行文件 IO,则简单地删除 IOError 并不是一个好的解决方案。尽管这里提到了,但由于某种原因,我无法捕获 BrokenPipeError。
找到一篇关于恢复 sigpipe 的默认信号处理程序的博文:http://newbebweb.blogspot.com/2012/02/python-head-ioerror-errno-32-broken.html
简而言之,您可以在大部分输出之前将以下内容添加到脚本中:
if log.isEnabledFor(logging.DEBUG): # optional
# set default handler to no-op
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
这似乎发生在 head 上,但不是其他程序,例如 grep --- 正如提到的 head 关闭标准输出。如果您不经常在脚本中使用 head,则可能不值得担心。
【讨论】:
太棒了!感谢您的解释和文章!以上是关于打印大量格式化数据时如何避免Broken Pipe错误?的主要内容,如果未能解决你的问题,请参考以下文章