Python 的标准输出作为管道输入出现 Broken pipe 错误?

版权声明:本文为博主原创文章,转载请注明原文出处。 https://blog.csdn.net/woay2008/article/details/83592298

今天写 Python2 程序遇到一个问题,为说明这个问题,写一个演示程序,它的代码如下:

import sys

for line in sys.stdin:
    print line.strip('\n')

该演示程序的功能就是从标准输入读取内容输出到标准输出,当以如下方式使用时程序会报错:

ps -elf | python test_pipe.py | head -n 10

报错内容如下:

Traceback (most recent call last):
  File "test_pipe.py", line 6, in <module>
    print line.strip('\n')
IOError: [Errno 32] Broken pipe

而将head命令换成tail命令则不会报错。

网上搜索了下,找到了解决方法。解决方法如下:

import sys
from signal import signal, SIGPIPE, SIG_DFL

# 让 python 忽略 SIGPIPE 信号,并且不抛出异常
signal(SIGPIPE,SIG_DFL) 

for line in sys.stdin:
    print line.strip('\n')

该问题产生的原因是:head程序从管道的一端读取到足够的数据后就会关闭管道,而python程序正在管道的另一端写入,于是python程序就会接收到SIGPIPE信号使程序异常退出。而tail命令是等管道写入完成后再关闭管道,所以不会有这个问题。

上面简单的程序有个不足之处:如果标准输入没有数据,程序将会一直阻塞。我们希望标准输入没有数据时,程序能够退出。这时可以使用 poll 轮询标准输入,在一定的时间内没有收集到读事件,则退出程序。代码如下:

# -*- coding: utf-8 -*-
import os
import sys
import fcntl
import select

from signal import signal, SIGPIPE, SIG_DFL

# 让 python 忽略 SIGPIPE 信号,并且不抛出异常
signal(SIGPIPE, SIG_DFL)

fd = sys.stdin.fileno()
# 将标准输入的描述符设置成非阻塞
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK | fl) 

poll = select.poll()
poll.register(fd, select.POLLIN)

while True:

    events = poll.poll(100)
    if not events:
        break

    data = sys.stdin.read()
    if not data:
        break

    sys.stdout.write(data)

参考 : stackoverflow.

猜你喜欢

转载自blog.csdn.net/woay2008/article/details/83592298