如何打印大量格式化数据时,为了避免损坏的管道错误?(How to avoid a Broken Pi

2019-08-19 06:57发布

我想打印我的格式化的元组的列表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}\t{1:%d}\t{2:%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 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

谁可以帮我这个事?

我试图把printtry-except块来处理错误,但在那之后有一个在控制台另一条消息:

close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

我也试图通过连续两次立即刷新数据sys.stdout.writesys.stdout.flush电话,但没有happend ..

Answer 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


Answer 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'>


Answer 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但没有堆栈跟踪。

这似乎是书写工具,输出管道的最小修复。



Answer 4:

有这个问题与Python3和调试日志记录管道输送到头部为好。 如果你的脚本会谈到网络或进行文件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)

这似乎与头部发生,但没有其他程序,如grep的---如提到的头标准输出关闭。 如果你没有用脚本经常用头,它可能不值得担心。



文章来源: How to avoid a Broken Pipe error when printing a large amount of formatted data?