IOError: [Error 32] Tubería rota: Python


Tengo un script 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 redirigiendo la salida, por lo que si el script anterior fue nombrado "open.py", entonces mi orden de correr sería:

open.py | othercommand
Author: ks1322, 2013-01-08

7 answers

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

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

Usted podría coger el tubo roto? Esto escribe el archivo en stdout línea por línea hasta que se cierra 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 othercommand está leyendo desde la tubería antes de que se vuelva demasiado grande - https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer

 25
Author: Alex L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 12:36:27

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 el fondo de esta solución. Mejor respuesta aquí.

 102
Author: akhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-29 06:38:56

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

  • Señal estándar Unix SIGPIPE se envía a un proceso escribiendo a una tubería cuando no hay ningún proceso leyendo desde la tubería (ya).

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

  • Por diseño, sin embargo, Python sí mismo trampas SIGPIPE y lo traduce en un Python IOError instancia con errno valor errno.EPIPE, para que un script de Python pueda atraparla, si así lo desea - vea La respuesta de Alex L. para saber cómo hacerlo.

  • Si un script de Python no lo captura , Python muestra un mensaje de errorIOError: [Errno 32] Broken pipe y termina el script con el código de salida 1 - este es el síntoma de la OP Sierra.

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

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

      from signal import signal, SIGPIPE, SIG_DFL
      signal(SIGPIPE, SIG_DFL) 
      
 60
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:47

Se produce un error de "Tubería rota" cuando intenta escribir en una tubería que se ha cerrado en el otro extremo. Dado que el código que has mostrado no involucra ninguna tubería directamente, sospecho que estás 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 escribe (vía print) para fallar 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 has reportado.

 23
Author: Blckknght,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-08 11:10:14

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

signal(SIGPIPE, SIG_DFL) 

Es de hecho peligroso (como ya sugirió David Bennet en los comentarios) y en mi caso condujo a funny business dependiente de la plataforma cuando se combina con multiprocessing.Manager (porque la biblioteca estándar se basa en BrokenPipeError que se plantea en varios lugares). Para hacer una larga y dolorosa historia corta, así es como la arreglé:

Primero, necesitas coger el 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 todavía puede imprimir un mensaje como este:

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

Desafortunadamente 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 un decorador, puede envolver su función principal con (sí, eso es una sangría loca):

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
 15
Author: trehn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-03 20:05:39

Esto también puede ocurrir si el final de lectura de la salida de su script muere prematuramente

Ie open.py / Otros comandos

Si otro comando sale y open.py intenta escribir en stdout

Tuve un mal guión gawk que hizo esto encantador para mí.

 1
Author: lkreinitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-17 18:23:24

Los cierres deben hacerse en orden inverso de los aperturas.

 0
Author: Paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-28 10:19:59