Saya memiliki skrip Python 3 yang sangat sederhana:
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()
Tapi selalu tertulis:
IOError: [Errno 32] Broken pipe
Saya melihat di internet semua cara rumit untuk memperbaikinya, tetapi saya menyalin kode ini secara langsung, jadi saya pikir ada yang salah dengan kode dan bukan SIGPIPE Python.
Saya mengarahkan output, jadi jika skrip di atas bernama "open.py", maka perintah saya untuk menjalankan adalah:
open.py | othercommand
python
python-3.x
sigpipe
JOHANNES_NYÅTT
sumber
sumber
print(f1.readlines())
a.txt
dan tulis kestdout
. Mungkin coba pisahkan menjadi baris terpisah sehingga Anda dapat melihat operasi mana yang memicu pengecualian. Jikastdout
pipa dan ujung baca telah ditutup, maka itu bisa menjelaskanEPIPE
kesalahan.print
panggilan tersebut adalah pelakunya. @ JOHANNES_NYÅTT, dapatkah Anda menjelaskan bagaimana Anda meluncurkan skrip Python Anda? Apakah Anda mengarahkan keluaran standar ke suatu tempat?Jawaban:
Saya belum mereproduksi masalah, tetapi mungkin metode ini akan menyelesaikannya: (menulis baris demi baris
stdout
daripada menggunakanprint
)import sys with open('a.txt', 'r') as f1: for line in f1: sys.stdout.write(line)
Anda bisa menangkap pipa yang rusak? Ini menulis file ke
stdout
baris demi baris sampai pipa ditutup.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
Anda juga perlu memastikan bahwa
othercommand
membaca dari pipa sebelum menjadi terlalu besar - /unix/11946/how-big-is-the-pipe-buffersumber
print
panggilan, bukan dengan membaca file).Masalahnya karena penanganan SIGPIPE. Anda dapat mengatasi masalah ini menggunakan kode berikut:
from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE,SIG_DFL)
Lihat di sini untuk latar belakang solusi ini. Jawaban yang lebih baik di sini .
sumber
Untuk menghadirkan jawaban Alex L. yang bermanfaat , jawaban akhan yang membantu , dan jawaban membantu Blckknght bersama dengan beberapa informasi tambahan:
Sinyal Unix standar
SIGPIPE
dikirim ke proses penulisan ke pipa ketika tidak ada proses membaca dari pipa (lagi).head
dengan desain berhenti membaca sebelum waktunya dari pipa, setelah mereka menerima cukup data.Secara default - yaitu, jika proses penulisan tidak secara eksplisit menjebak
SIGPIPE
- proses penulisan dihentikan begitu saja , dan kode keluarnya disetel ke141
, yang dihitung sebagai128
(untuk menghentikan sinyal oleh sinyal secara umum) +13
( nomorSIGPIPE
sinyal khusus ) .Secara desain, bagaimanapun, Python sendiri menjebak
SIGPIPE
dan menerjemahkannya ke dalamIOError
instance Python denganerrno
nilaierrno.EPIPE
, sehingga skrip Python dapat menangkapnya, jika memang mau - lihat jawaban Alex L. untuk cara melakukannya.Jika Python Script tidak tidak menangkapnya , Python pesan kesalahan output
IOError: [Errno 32] Broken pipe
dan berakhir script dengan kode keluar1
- ini adalah gejala OP saw.Dalam banyak kasus, ini lebih mengganggu daripada membantu , jadi kembali ke perilaku default diinginkan :
Menggunakan
signal
modul memungkinkan hal itu, seperti yang dinyatakan dalam jawaban akhan ;signal.signal()
mengambil sinyal untuk ditangani sebagai argumen pertama dan penangan sebagai argumen kedua; nilai penangan khususSIG_DFL
mewakili perilaku default sistem :from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE, SIG_DFL)
sumber
Galat "Pipa Rusak" terjadi saat Anda mencoba untuk menulis ke pipa yang telah ditutup di ujung lainnya. Karena kode yang Anda tunjukkan tidak melibatkan pipa apa pun secara langsung, saya curiga Anda melakukan sesuatu di luar Python untuk mengarahkan output standar interpreter Python ke tempat lain. Ini bisa terjadi jika Anda menjalankan skrip seperti ini:
Masalah yang Anda hadapi
someothercommand
adalah keluar tanpa membaca semua yang tersedia di input standarnya. Ini menyebabkan Anda menulis (melaluiprint
) gagal di beberapa titik.Saya dapat mereproduksi kesalahan dengan perintah berikut di sistem Linux:
python -c 'for i in range(1000): print i' | less
Jika saya menutup
less
pager tanpa menggulir semua inputnya (1000 baris), Python keluar dengan yang sama seperti yangIOError
Anda laporkan.sumber
SIGPIPE
sinyal tidak selalu menunjukkan kondisi kesalahan ; beberapa utilitas Unix, terutamahead
, dengan desain, selama operasi normal menutup pipa lebih awal, setelah mereka membaca data sebanyak yang mereka butuhkan.Saya merasa berkewajiban untuk menunjukkan bahwa metode yang digunakan
memang berbahaya (seperti yang sudah disarankan oleh David Bennet di komentar) dan dalam kasus saya menyebabkan bisnis lucu yang bergantung pada platform bila digabungkan dengan
multiprocessing.Manager
(karena pustaka standar bergantung pada BrokenPipeError yang dimunculkan di beberapa tempat). Singkatnya, begini cara saya memperbaikinya:Pertama, Anda perlu menangkap
IOError
(Python 2) atauBrokenPipeError
(Python 3). Bergantung pada program Anda, Anda dapat mencoba keluar lebih awal pada saat itu atau mengabaikan pengecualian: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
Namun, ini belum cukup. Python 3 masih dapat mencetak pesan seperti ini:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> BrokenPipeError: [Errno 32] Broken pipe
Sayangnya menghilangkan pesan itu tidak langsung, tetapi akhirnya saya menemukan http://bugs.python.org/issue11380 di mana Robert Collins menyarankan solusi ini yang saya ubah menjadi dekorator yang dapat Anda bungkus dengan fungsi utama Anda (ya, itu gila lekukan):
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
sumber
Saya tahu ini bukan cara yang "tepat" untuk melakukannya, tetapi jika Anda hanya tertarik untuk menghilangkan pesan kesalahan, Anda dapat mencoba solusi berikut:
python your_python_code.py 2> /dev/null | other_command
sumber
Jawaban teratas (
if e.errno == errno.EPIPE:
) di sini tidak benar-benar berhasil untuk saya. Saya mendapatkan:AttributeError: 'BrokenPipeError' object has no attribute 'EPIPE'
Namun, ini harus berfungsi jika yang Anda pedulikan hanyalah mengabaikan pipa yang rusak pada penulisan tertentu. Saya pikir ini lebih aman daripada menjebak SIGPIPE:
try: # writing, flushing, whatever goes here except BrokenPipeError: exit( 0 )
Anda jelas harus membuat keputusan, apakah kode Anda benar-benar selesai jika Anda terkena pipa yang rusak, tetapi untuk sebagian besar tujuan saya pikir itu biasanya benar. (Jangan lupa untuk menutup pegangan file, dll.)
sumber
Ini juga dapat terjadi jika akhir baca dari keluaran dari skrip Anda mati sebelum waktunya
yaitu open.py | otherCommand
jika otherCommand keluar dan open.py mencoba menulis ke stdout
Saya memiliki skrip melongo yang buruk yang membuat saya senang.
sumber
head
, berdasarkan desain, selama operasi normal menutup pipa lebih awal, setelah mereka membaca data sebanyak yang mereka butuhkan. Kebanyakan CLI hanya tunduk pada sistem untuk perilaku defaultnya: secara diam-diam menghentikan proses membaca dan melaporkan kode keluar141
(yang, dalam shell, tidak langsung terlihat, karena perintah terakhir pipeline menentukan kode keluar keseluruhan). Perilaku default Python , sayangnya, adalah mati dengan berisik .Penutupan harus dilakukan dalam urutan terbalik dari pembukaan.
sumber