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 résoudre ce problème, 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 était nommé "open.py", ma commande à exécuter serait:
open.py | othercommand
python
python-3.x
sigpipe
JOHANNES_NYÅTT
la source
la source
print(f1.readlines())
a.txt
et une écriture versstdout
. Essayez peut-être de les diviser sur des lignes séparées afin de voir quelle opération déclenche l'exception. Sistdout
est un tube et que la fin de lecture a été fermée, cela pourrait expliquer l'EPIPE
erreur.print
appel est le coupable. @ JOHANNES_NYÅTT, pouvez-vous clarifier comment vous lancez votre script Python? Redirigez-vous la sortie standard quelque part?Réponses:
Je n'ai pas reproduit le problème, mais peut-être que cette méthode le résoudrait: (écrire ligne par ligne
stdout
plutôt que d'utiliserprint
)import sys with open('a.txt', 'r') as f1: for line in f1: sys.stdout.write(line)
Vous pourriez attraper le tuyau cassé? Cela écrit le fichier
stdout
ligne par ligne jusqu'à ce que le tuyau soit fermé.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 la
othercommand
lecture est effectuée à partir du tube avant qu'il ne devienne trop gros - /unix/11946/how-big-is-the-pipe-bufferla source
print
appel, pas à la lecture des fichiers).Le problème est dû à la gestion SIGPIPE. Vous pouvez résoudre ce problème à l'aide du code suivant:
from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE,SIG_DFL)
Voir ici pour le contexte de cette solution. Meilleure réponse ici .
la source
Pour apporter réponse utile Alex L. , réponse utile de Akhan et réponse utile de Blckknght ainsi que des informations supplémentaires:
Le signal Unix standard
SIGPIPE
est envoyé à un processus qui écrit sur un tube lorsqu'il n'y a plus de lecture de processus depuis le tube.head
par conception arrêtent de lire prématurément à partir d'un tube, une fois qu'ils ont reçu suffisamment de données.Par défaut - c'est-à-dire, si le processus d'écriture ne piège pas explicitement
SIGPIPE
- le processus d'écriture est simplement terminé , et son code de sortie est mis à141
, qui est calculé comme128
(pour signaler la fin par le signal en général) +13
(SIGPIPE
le numéro de signal spécifique de ) .De par sa conception, cependant, Python lui-même le piège
SIGPIPE
et le traduit en uneIOError
instance Python avec uneerrno
valeurerrno.EPIPE
, afin qu'un script Python puisse l'attraper, s'il le souhaite - voir la réponse d'Alex L. pour savoir comment faire.Si un python de script ne pas l' attraper , Python message d'erreur de
IOError: [Errno 32] Broken pipe
et termine le script avec le code de sortie1
- c'est le symptôme de la scie OP.Dans de nombreux cas, cela est plus perturbateur qu'utile , il est donc souhaitable de revenir au comportement par défaut :
L'utilisation du
signal
module permet justement cela, comme indiqué dans la réponse d'Akhan ;signal.signal()
prend un signal à traiter comme 1er argument et un gestionnaire comme 2ème; la valeur du gestionnaire spécialSIG_DFL
représente le comportement par défaut du système :from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE, SIG_DFL)
la source
Une erreur "Broken Pipe" se produit lorsque vous essayez d'écrire dans un canal qui a été fermé à l'autre extrémité. Puisque le code que vous avez montré n'implique aucun tube directement, je suppose 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:
Le problème que vous avez est que vous
someothercommand
quittez sans lire tout ce qui est disponible sur son entrée standard. Cela provoque votre écriture (viaprint
échec de ) à 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
less
pager sans faire défiler toutes ses entrées (1000 lignes), Python sort avec le même queIOError
vous avez signalé.la source
SIGPIPE
signal ne signifie pas nécessairement une erreur état, certains utilitaires Unix, notammenthead
, par la conception, pendant le fonctionnement normal près du tuyau au début, une fois qu'ils ont lu autant de données que ils avaient besoin.Je me sens obligé de préciser que la méthode utilisant
est en effet dangereux (comme déjà suggéré par David Bennet dans les commentaires) et dans mon cas, a conduit à des activités amusantes dépendant de la plate-forme lorsqu'il est combiné avec
multiprocessing.Manager
(car la bibliothèque standard repose sur BrokenPipeError soulevé à plusieurs endroits). Pour faire une histoire longue et douloureuse, voici comment je l'ai corrigée:Tout d'abord, vous devez attraper le
IOError
(Python 2) ouBrokenPipeError
(Python 3). En fonction de votre programme, vous pouvez essayer de quitter tôt à ce stade ou 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 toujours 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 cette solution de contournement que j'ai transformée en décorateur avec lequel vous pouvez envelopper votre fonction principale (oui, c'est un peu fou échancrure):
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
la source
Je sais que ce n'est pas la manière «appropriée» de le faire, mais si vous souhaitez simplement vous débarrasser du message d'erreur, vous pouvez essayer cette solution de contournement:
python your_python_code.py 2> /dev/null | other_command
la source
La réponse principale (
if e.errno == errno.EPIPE:
) ici n'a pas vraiment fonctionné pour moi. J'ai eu:AttributeError: 'BrokenPipeError' object has no attribute 'EPIPE'
Cependant, cela devrait fonctionner si tout ce dont vous vous souciez est d'ignorer les tuyaux cassés sur des écritures spécifiques. Je pense que c'est plus sûr que de piéger SIGPIPE:
try: # writing, flushing, whatever goes here except BrokenPipeError: exit( 0 )
Vous devez évidemment prendre une décision quant à savoir si votre code est vraiment, vraiment fait si vous frappez le tuyau cassé, mais pour la plupart des cas, je pense que cela sera généralement vrai. (N'oubliez pas de fermer les descripteurs de fichiers, etc.)
la source
Cela peut également se produire si la fin de lecture de la sortie de votre script meurt prématurément
ie open.py | autreCommande
si otherCommand se ferme et open.py essaie d'écrire dans stdout
J'ai eu un mauvais script qui m'a fait du bien.
la source
head
, par la conception, pendant le fonctionnement normal près du tuyau au début, une fois qu'ils ont lu autant de données que leur besoin. La plupart des CLI s'en remettent simplement au système pour son comportement par défaut: terminer discrètement le processus de lecture et signaler le code de sortie141
(ce qui, dans un shell, n'est pas évident, car la dernière commande d' un pipeline détermine le code de sortie global). Le comportement par défaut de Python , malheureusement, est de mourir bruyamment .Les fermetures doivent être effectuées dans l'ordre inverse des ouvertures.
la source