python python-3.x sigpipe

IOError:[Errno 32] Broken pipe: Python



python-3.x sigpipe (7)

El problema se debe al manejo de SIGPIPE. Puede resolver este problema usando el siguiente código:

from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE,SIG_DFL)

Vea aquí para obtener antecedentes sobre esta solución.

Tengo un script de Python 3 muy simple:

f1 = open(''a.txt'', ''r'') print(f1.readlines()) f2 = open(''b.txt'', ''r'') print(f2.readlines()) f3 = open(''c.txt'', ''r'') print(f3.readlines()) f4 = open(''d.txt'', ''r'') print(f4.readlines()) f1.close() f2.close() f3.close() f4.close()

Pero siempre dice:

IOError: [Errno 32] Broken pipe

Vi en Internet todas las formas complicadas de arreglar esto, pero copié este código directamente, así que creo que hay algo mal con el código y no con el SIGPIPE de Python.

Estoy redireccionando el resultado, por lo que si el script anterior se llamara "open.py", entonces mi comando para ejecutar sería:

open.py | othercommand


Esto también puede ocurrir si el final de lectura del resultado de su script muere prematuramente

es decir, open.py | otherCommand

si otherCommand sale y open.py intenta escribir en stdout

Tenía un guión malo que me hizo esto encantador.


Los cierres deben hacerse en orden inverso al de las aperturas.


Me siento obligado a señalar que el método de uso

signal(SIGPIPE, SIG_DFL)

es realmente peligroso (como ya sugirió David Bennet en los comentarios) y en mi caso condujo a negocios divertidos dependientes de la plataforma cuando se combinó con multiprocessing.Manager Administrador (porque la biblioteca estándar se basa en que BrokenPipeError se generó en varios lugares). Para resumir una historia larga y dolorosa, así es como lo arreglé:

En primer lugar, debe detectar IOError (Python 2) o BrokenPipeError (Python 3). Dependiendo de su programa, puede intentar salir temprano en ese punto o simplemente ignorar la excepción:

from errno import EPIPE try: broken_pipe_exception = BrokenPipeError except NameError: # Python 2 broken_pipe_exception = IOError try: YOUR CODE GOES HERE except broken_pipe_exception as exc: if broken_pipe_exception == IOError: if exc.errno != EPIPE: raise

Sin embargo, esto no es suficiente. Python 3 aún puede imprimir un mensaje como este:

Exception ignored in: <_io.TextIOWrapper name=''<stdout>'' mode=''w'' encoding=''UTF-8''> BrokenPipeError: [Errno 32] Broken pipe

Lamentablemente, deshacerse de ese mensaje no es sencillo, pero finalmente encontré http://bugs.python.org/issue11380 donde Robert Collins sugiere esta solución que convertí en decoradora con la que puedes envolver tu función principal (sí, eso es un poco loco sangría):

from functools import wraps from sys import exit, stderr, stdout from traceback import print_exc def suppress_broken_pipe_msg(f): @wraps(f) def wrapper(*args, **kwargs): try: return f(*args, **kwargs) except SystemExit: raise except: print_exc() exit(1) finally: try: stdout.flush() finally: try: stdout.close() finally: try: stderr.flush() finally: stderr.close() return wrapper @suppress_broken_pipe_msg def main(): YOUR CODE GOES HERE


No he reproducido el problema, pero tal vez este método lo resolvería: (escribiendo línea por línea para stdout lugar de usar print )

import sys with open(''a.txt'', ''r'') as f1: for line in f1: sys.stdout.write(line)

¿Podrías atrapar la tubería rota? Esto escribe el archivo en stdout línea por línea hasta que se cierre la tubería.

import sys, errno try: with open(''a.txt'', ''r'') as f1: for line in f1: sys.stdout.write(line) except IOError as e: if e.errno == errno.EPIPE: # Handle error

También debe asegurarse de que el otro othercommand esté leyendo antes de que se othercommand demasiado grande - https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer


Para traer la respuesta útil de Alex L., la respuesta útil de Akhan y la útil respuesta de Blckknght junto con información adicional:

  • La señal estándar de Unix, SIGPIPE se envía a un proceso de escritura en una pipe cuando ya no hay lectura de proceso desde la tubería (más).

    • Esto no es necesariamente una condición de error ; algunas utilidades de Unix, como la head por diseño, dejan de leer prematuramente desde una tubería, una vez que han recibido suficientes datos.
  • Por defecto , es decir, si el proceso de escritura no atrapa SIGPIPE explícitamente, el proceso de escritura simplemente finaliza y su código de salida se establece en 141 , que se calcula como 128 (para terminar la señal por señal en general) + 13 ( SIGPIPE '' s número de señal específico).

  • Sin embargo, por diseño, Python atrapa a SIGPIPE y lo traduce a una instancia de Python IOError con errno value errno.EPIPE , de modo que un script de Python puede atraparlo, si así lo desea, ver la respuesta de Alex L. sobre cómo hacerlo .

  • Si un script de Python no lo IOError: [Errno 32] Broken pipe , Python genera el mensaje de error IOError: [Errno 32] Broken pipe y finaliza el script con el código de salida 1 - este es el síntoma que vio el OP.

  • En muchos casos, esto es más perturbador que útil , por lo que es deseable volver al comportamiento predeterminado :

    • Usar el módulo de signal permite eso, como se indica en la respuesta de akhan ; signal.signal() toma una señal para manejar como primer argumento y un manejador como segundo; valor especial del controlador SIG_DFL representa el comportamiento predeterminado del sistema:

      from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE, SIG_DFL)


Se produce un error de "Rotura de tubería" cuando intenta escribir en una tubería que se ha cerrado en el otro extremo. Dado que el código que ha mostrado no involucra ninguna canalización directamente, sospecho que está haciendo algo fuera de Python para redirigir la salida estándar del intérprete de Python a otro lugar. Esto podría suceder si está ejecutando un script como este:

python foo.py | someothercommand

El problema que tiene es que someothercommand está saliendo sin leer todo lo disponible en su entrada estándar. Esto hace que su escritura (a través de la print ) falle en algún momento.

Pude reproducir el error con el siguiente comando en un sistema Linux:

python -c ''for i in range(1000): print i'' | less

Si cierro el buscapersonas less sin desplazarme por toda su entrada (1000 líneas), Python sale con el mismo IOError que ha informado.