IOError: [Errno 32] broken pipe: Python
j'ai un script Python 3 très 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()
mais il dit toujours:
IOError: [Errno 32] Broken pipe
j'ai vu sur internet toutes les façons compliquées de corriger cela, mais j'ai copié ce code directement, donc je pense qu'il y a quelque chose qui ne va pas avec le code et pas le SIGPIPE de Python.
je redirige la sortie, Donc si le script ci-dessus a été nommé "open.py", alors ma commande à exécuter serait:
open.py | othercommand
7 réponses
Je n'ai pas reproduit la question, mais peut-être cette méthode résoudrait-elle: (écrire ligne par ligne à stdout
plutôt que d'utiliser print
)
import sys
with open('a.txt', 'r') as f1:
for line in f1:
sys.stdout.write(line)
vous pourriez attraper le tuyau cassé? Ceci écrit le dossier à stdout
ligne par ligne jusqu'à ce que la pipe soit fermée.
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
vous devez également vous assurer que othercommand
est la lecture de la pipe avant qu'elle ne devienne trop grande - https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer
apporter Alex L. de réponse utile , akhan de réponse utile , et Blckknght de réponse utile avec quelques informations supplémentaires:
-
Standard Unix signal
SIGPIPE
est envoyé à un processus écriture à un pipe quand il n'y a pas de processus lire de la pipe (ou plus).- ce n'est pas nécessairement une erreur condition; certains utilitaires Unix tels que
head
par conception arrêter de lire prématurément à partir d'une pipe, une fois qu'ils ont reçu suffisamment de données.
- ce n'est pas nécessairement une erreur condition; certains utilitaires Unix tels que
-
par défaut - i.e., si le processus d'écriture n'est pas explicitement piège
SIGPIPE
- le processus d'écriture est simplement terminé , et son code de sortie est réglé à141
, qui est calculé comme128
(à la fin du signal par signal en général) +13
(SIGPIPE
's signal spécifique numéro ). -
de Par sa conception, cependant, Python lui-même traps
SIGPIPE
et le traduit en un pythonIOError
instance avecerrno
valeurerrno.EPIPE
, de sorte qu'un script Python peut l'attraper, s'il le souhaite - voir la réponse D'Alex L. pour savoir comment faire cela. -
Si un Python script ne pas l'attraper , Python erreur sur les sorties le message
IOError: [Errno 32] Broken pipe
et termine le script avec le code de sortie1
- c'est le symptôme que L'OP a vu. -
Dans de nombreux cas c'est plus d'inconvénients que d'utile , donc de revenir au comportement par défaut est souhaitable :
-
utilisant le
signal
le module permet justement cela, comme indiqué dans la réponse d'akhan ;signal.signal()
prend un signal à manipuler comme premier argument et un handler comme deuxième; valeur de handler spécialeSIG_DFL
représente le système par défaut comportement:from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE, SIG_DFL)
-
une erreur de "Pipe cassée" se produit lorsque vous essayez d'écrire à une pipe qui a été fermée à l'autre extrémité. Puisque le code que vous avez montré n'implique pas de pipes directement, je soupçonne que vous faites quelque chose en dehors de Python pour rediriger la sortie standard de L'interpréteur Python vers un autre endroit. Cela peut arriver si vous exécutez un script comme celui-ci:
python foo.py | someothercommand
le problème que vous avez est que someothercommand
sort sans lire tout disponible sur son entrée standard. Cela provoque l'échec de votre écriture (via print
) à un moment donné.
j'ai pu reproduire l'erreur avec la commande suivante sur un système Linux:
python -c 'for i in range(1000): print i' | less
si je ferme le pager less
sans faire défiler toutes ses entrées (1000 lignes), Python sort avec le même IOError
que vous avez signalé.
je me sens obligé de souligner que la méthode utilisant
signal(SIGPIPE, SIG_DFL)
est en effet dangereux (comme déjà suggéré par David Bennet dans les commentaires) et dans mon cas a conduit à plate-forme-dépendante funny business lorsqu'il est combiné avec multiprocessing.Manager
(parce que la bibliothèque standard repose sur BrokenPipeError étant soulevé à plusieurs endroits). Pour faire court à une histoire longue et douloureuse, voici comment je l'ai corrigé:
D'abord, vous devez attrapez le IOError
(Python 2) ou BrokenPipeError
(Python 3). Selon votre programme, vous pouvez essayer un départ anticipé à ce point ou tout simplement ignorer l'exception:
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
cependant, cela ne suffit pas. Python 3 peut encore imprimer un message comme celui-ci:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
malheureusement, se débarrasser de ce message n'est pas simple, mais j'ai finalement trouvé http://bugs.python.org/issue11380 où Robert Collins suggère ce contournement que j'ai transformé en décorateur, vous pouvez envelopper votre fonction principale avec (Oui, c'est une indentation folle):
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
cela peut également se produire si la fin de la lecture de la sortie de votre script meurt prématurément
ie open.py 151910920"
si une autre marque open.py essaie d'écrire à stdout
j'ai eu un mauvais script gawk qui m'a fait cette belle à moi.