11

我正在尝试打印在我的stdout. 为此,我使用str.format方法。head一切正常,但是当我使用命令 a管道输出以查看第一行时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

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调用立即刷新数据 ,但什么也没发生。

4

4 回答 4

13

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
于 2013-04-03T17:26:00.580 回答
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'>
于 2016-05-17T20:18:22.460 回答
2

一般来说,我会尝试捕捉我能逃脱的最具体的错误。在这种情况下,它是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 但没有堆栈跟踪。

这似乎是编写输出到管道的工具的最低限度的修复。

于 2017-03-07T23:47:00.847 回答
1

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)

这似乎发生在 head 上,但不是其他程序,如 grep ——正如提到的 head 关闭标准输出。如果您不经常在脚本中使用 head,则可能不值得担心。

于 2017-10-14T17:57:09.860 回答