Bagaimana saya bisa memperbaiki kesalahan Pipa Rusak?

36

Saya baru-baru ini menginstal ulang RVM (mengikuti instruksi di http://rvm.io ) setelah menginstal Ubuntu 12.10 baru ketika saya mendapat Drive SSD.

Sekarang, ketika saya mengetik: type rvm | head -1

Saya menerima kesalahan berikut:

rvm is a function
-bash: type: write error: Broken pipe

Tetapi jika saya segera mengulangi perintah maka saya hanya menerima:

rvm is a function

Dan tampaknya semuanya baik-baik saja? Apa yang terjadi? Apa yang bisa saya lakukan untuk memperbaikinya? Itu tidak selalu terjadi. Tampaknya lebih sporadis. Saya sudah mencoba menemukan beberapa pola untuk itu tetapi belum.

Jason Shultz
sumber

Jawaban:

57

Melihat "Pipa rusak" dalam situasi ini jarang terjadi, tetapi normal.

Saat Anda menjalankan type rvm | head -1, bash dieksekusi type rvmdalam satu proses, head -1dalam proses lainnya. 1 Stdout of typeterhubung ke ujung "tulis" pipa , stdin dari headke ujung "baca". Kedua proses berjalan pada saat bersamaan.

The head -1proses membaca data dari stdin (biasanya dalam potongan 8 kB), print satu baris (menurut -1pilihan), dan keluar, menyebabkan "membaca" ujung pipa harus ditutup. Karena rvmfungsinya cukup panjang (sekitar 11 kB setelah diuraikan dan direkonstruksi oleh bash), ini berarti headkeluar sementara typemasih memiliki beberapa kB data untuk ditulis.

Pada titik ini, karena typesedang mencoba untuk menulis ke pipa yang ujungnya telah ditutup - pipa yang rusak - fungsi write () yang akan mengembalikan kesalahan EPIPE, diterjemahkan sebagai "Pipa rusak". Selain kesalahan ini, kernel juga mengirimkan sinyal SIGPIPE ke type, yang secara default membunuh proses segera.

(Sinyal ini sangat berguna dalam shell interaktif, karena sebagian besar pengguna tidak ingin proses pertama tetap berjalan dan mencoba menulis ke mana-mana. Sementara itu, layanan non-interaktif mengabaikan SIGPIPE - itu tidak akan baik untuk daemon yang sudah berjalan lama untuk mati karena kesalahan sederhana - sehingga mereka menemukan kode kesalahan sangat berguna.)

Namun, pengiriman sinyal tidak 100% langsung, dan mungkin ada kasus di mana write () mengembalikan EPIPE dan proses terus berjalan untuk sementara waktu sebelum menerima sinyal. Dalam hal ini, typedapatkan waktu yang cukup untuk memperhatikan penulisan yang gagal, menerjemahkan kode kesalahan dan bahkan mencetak pesan kesalahan ke stderr sebelum dibunuh oleh SIGPIPE. (Pesan kesalahan mengatakan "-bash: type:" karena typemerupakan perintah built-in dari bash itu sendiri.)

Ini tampaknya lebih umum pada sistem multi-CPU, karena typeproses dan kode pengiriman sinyal kernel dapat berjalan pada core yang berbeda, secara harfiah pada saat yang sama.

Mungkin untuk menghapus pesan ini dengan menambal typebuiltin (dalam kode sumber bash) untuk segera keluar ketika menerima EPIPE dari fungsi write ().

Namun, tidak ada yang perlu dikhawatirkan, dan itu tidak terkait dengan rvminstalasi Anda dengan cara apa pun.

grawity
sumber
Terima kasih! Saya khawatir tentang hal itu. Saya melakukan sekitar satu jam senilai googling semalam memecahkan masalah instalasi rvm saya dan melakukan perbaikan untuk itu mencoba memperbaikinya. Saya baru saja bertukar dengan drive SSD dan menggunakan LVM dan mengenkripsi hard drive sehingga ada banyak variabel yang ikut bermain dan saya hanya tidak yakin apa yang mungkin terjadi ke samping. Terima kasih telah menenangkan pikiran saya!
Jason Shultz
Saya telah mengirimkan hasil lsmelalui pipa head -1selama bertahun-tahun, dan hari ini saya menerima pesan pipa yang rusak.
Tulains Córdova
1
(Catatan: Kesalahan "Rusak pipa" tidak datang dari sinyal. Itu berasal dari errno . Sementara shell mungkin menampilkan pesan teks untuk keluar yang diinduksi sinyal, biasanya cukup pintar untuk berpura-pura bahwa keluar SIGPIPE adalah 'bersih' satu.)
grawity
23

Anda dapat memperbaiki pipa yang rusak dengan mengorbankan proses lain dengan memasukkan tail -n +1pipa Anda, seperti ini:

ketik rvm | tail -n +1 | kepala -1

Ia +1memberitahu tailuntuk mencetak baris input pertama dan segala sesuatu yang mengikuti. Output akan persis sama seperti jika tail -n +1tidak ada di sana, tetapi program ini cukup pintar untuk memeriksa output standar dan menutup pipa dengan bersih. Tidak ada lagi pipa yang rusak .

Huuu
sumber
1
Trik yang bagus. Saya telah menggunakan dalam situasi yang berbeda dari yang disediakan di sini. Terima kasih!
Seseorang masih menggunakan Anda MS-DOS
6
Tampak seperti solusi yang bagus, tetapi pada Ubuntu 14.04.2 dengan ekor 8.21 saya mendapatkan "tail: write error: Broken pipe", yang tidak ada perbaikan.
Roger Dueck
2
@RogerDueck benar. Saya juga melihat ini pada sistem Mandriva untuk jenis masalah serupa yang bisa find /var/lib/mysql -xdev -type f -daystart -mmin +5 -print0 | xargs -0 ls -ldt | tail -n +1 | headdiandalkan xargs: ls: terminated by signal 13. Seperti yang kita tahu, masalahnya adalah salah satu input kelelahan dan hanya ada satu perintah yang berhubungan dengan buffering: dd. Menambahkan | dd obs=1Mke saluran pipa memperbaiki SIGPIPE untuk kasus penggunaan saya.
Andrew Beals
3
Saya akan lebih lanjut mengubah saran saya, meskipun saya akan mencatat bahwa saya tidak percaya bahwa xargs atau tipe harus kvetch tentang SIGPIPE, untuk ini: type rvm | (head -1 ; dd of=/dev/null) Ini, tentu saja, mirip dengan saran lain karena menyebabkan semua input diproses , tetapi ddharus menjadi program yang paling efisien untuk menangani hal-hal seperti itu.
Andrew Beals
3
Komentar tentang pelanggar SIGPIPE di sini: mail-index.netbsd.org/tech-userlevel/2013/01/07/msg007110.html
Andrew Beals
2

The write error: Broken pipepesan mengacu pada proses penulisan yang mencoba untuk menulis ke pipa tanpa pembaca tersisa di akhir pembacaan yang pipa dan keadaan khusus bahwa SIGPIPEsinyal diatur untuk diabaikan baik oleh arus atau proses induk. Jika itu adalah proses induk yang ditetapkanSIGPIPE untuk diabaikan, tidak mungkin bagi proses anak untuk membatalkannya lagi dalam cangkang non-interacitive.

Namun, adalah mungkin untuk membunuh type rvmketika head -1berakhir dengan menggunakan subkulit eksplisit. Dengan cara ini kita bisa latar belakang type rvm, kirim typepidke head -1subkulit dan kemudian menerapkan perangkap di EXITsana untuk membunuh type rvmsecara eksplisit.

trap "" PIPE        # parent process sets SIGPIPE to be ignored
bash                # start child process
export LANG=C
# create a fake rvm function
eval "
rvm() {
$(printf 'echo line of rvm code %s\n' {1..10000})
}
"

# rvm is a function
# bash: type: write error: Broken pipe
type rvm | head -1

# kill type rvm when head -1 terminates
# sleep 0: do nothing but with external command
( (sleep 0; type rvm) & echo ${!} ; wait ${!} ) | 
    (trap 'trap - EXIT; kill "$typepid"; exit' EXIT; typepid="$(head -1)"; head -1)
zancox
sumber
Dari jawaban grawity: typedapatkan cukup waktu untuk memperhatikan penulisan yang gagal, terjemahkan kode kesalahan dan bahkan cetak pesan kesalahan ke stderr sebelum dibunuh oleh SIGPIPE . Saya pikir solusi Anda tidak mencegah proses produsen (di typesini) bereaksi terhadap penulisan yang gagal (karena pipa yang ditutup), bukan?
Piotr Dobrogost