$> set -o pipefail
$> fortune | head -1 > /dev/null && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ!" || echo "ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ"
ΠΠΎΠ²Π΅Π·Π»ΠΎ!
$> fortune | head -1 > /dev/null && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ!" || echo "ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ"
ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ
ia adalah fortune
program bersyarat tanpa exit(rand())
.
Boleh anda terangkan? apa yang tidak kena di sini?
Penyimpangan lirik-sejarah
Saya mula berkenalan dengan Heisenbug ini seperempat abad yang lalu. Kemudian untuk pintu masuk dalam FaxNET adalah perlu untuk mencipta beberapa utiliti melalui
Pengalaman saya sebelum ini menangani pepijat dalam sendmail dan uucp/upc menambah ketekunan saya dalam "pengendalian ralat menyeluruh." Tidak ada gunanya menyelami butiran cerita itu, tetapi saya bergelut dengan Heisenbug ini selama dua minggu selama 10-14 jam. Oleh itu, teringat, dan semalam kenalan lama ini singgah melawat lagi.
Jawapan TL;DR
Utiliti head
boleh tutup saluran dari fortune
ΡΡΠ°Π·Ρ sebaik sahaja dia membaca baris pertama. Jika fortune
mengeluarkan lebih daripada satu baris, kemudian panggilan yang sepadan write()
akan mengembalikan ralat atau laporan bahawa lebih sedikit bait dikeluarkan daripada yang diminta. Sebaliknya, ditulis dengan pengendalian ralat yang teliti fortune
mempunyai hak untuk menggambarkan keadaan ini dalam status keluarnya. Kemudian disebabkan pemasangan set -o pipefail
akan bekerja || echo "ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ"
.
Walau bagaimanapun, head
mungkin tidak sampai pada masanya tutup sebelum ini fortune
akan selesai mengeluarkan data. Kemudian ia akan berfungsi && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ!"
.
Dalam salah satu hari saya GNUMakefile
echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'
Diterjemah kepada manusia
Ia adalah perkara biasa di sini untuk --version
ia bertanya siapa dia, dan jika pilihan itu tidak disokong, maka tunas dimasukkan "Sila gunakan pengkompil GCC atau CLANG yang serasi".
seperti
#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"
Terus terang, saya tidak segera mengenali "kenalan" saya. Selain itu, projek itu telah diuji berkali-kali di Elbrus dan di bawah banyak pengedaran yang berbeza, termasuk Alt. Dengan pelbagai penyusun, versi GNU Make dan bash. Oleh itu, saya tidak mahu melihat kesilapan saya di sini.
Apabila cuba menghasilkan semula masalah dan/atau memahami perkara yang sedang berlaku, lebih banyak perkara pelik mula berlaku.
Ejaan baris arahan:
echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"
Sekali-sekala ia akan menghasilkan teks tambahan, kemudian tidak... Selalunya salah satu pilihan akan bertahan lama, tetapi jika anda mencucuk lebih lama, anda sentiasa mendapat kedua-duanya!
Sudah tentu, strace
By the way, seperti mana-mana harga diri strace
lebih suka untuk tidak membiak.
Jadi apa yang berlaku?
- Utiliti
head
mempunyai hak (atau lebih tepatnya, malah dipaksa) untuk menutup saluran yang dibaca sebaik sahaja ia membaca bilangan baris yang diminta. - Penulis program penjanaan data (dalam kes ini
cc
) boleh mencetak berbilang baris dan percuma lakukan ini melalui berbilang panggilanwrite()
. - Jika pembaca akan mempunyai masa untuk menutup saluran di sebelahnya sebelum tamat rakaman di pihak penulis, maka penulis akan menerima ralat.
- Program penulis berhak kedua-duanya mengabaikan ralat penulisan saluran dan mencerminkannya dalam kod penyiapan anda.
- Disebabkan pemasangan
set -o pipefail
kod penyiapan saluran paip akan menjadi bukan sifar (salah) jika hasilnya bukan sifar daripada sekurang-kurangnya satu elemen, dan kemudian ia akan berfungsi|| echo "Please use GCC or CLANG compatible compiler"
.
Mungkin terdapat variasi bergantung pada cara program penulis berfungsi dengan isyarat. Sebagai contoh, program mungkin ditamatkan secara tidak normal (dengan penjanaan automatik status penamatan bukan sifar/ralat), atau write()
akan mengembalikan hasil penulisan lebih sedikit bait daripada yang diminta dan ditetapkan errno = EPIPE
.
Siapa yang patut disalahkan?
Dalam kes yang diterangkan sedikit daripada segala-galanya. Ralat semasa mengendalikan masuk cc
(lcc:1.23.20:Sepβ4-2019:e2k-v3-linux) tidak berlebihan. Dalam kebanyakan kes, adalah lebih baik untuk tersilap berhati-hati, walaupun ini mendedahkan kecacatan secara tiba-tiba dalam boilerplate yang direka untuk tingkah laku tradisional.
Apa yang perlu dilakukan?
salah:
fortune | head -1 && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ, Π½ΠΎ Π²Ρ ΡΠΈΡΠΊΡΠ΅ΡΠ΅!" || echo "WTF?"
Betul:
-
(fortune && echo "Π£ΡΠΏΠ΅ΡΠ½ΠΎ" || echo "ΠΡΠΈΠ±ΠΊΠ°") | head -1
Di sini, penutupan awal paip akan dikendalikan oleh penterjemah arahan apabila menservis saluran paip bersarang ("dalam" kurungan). Sehubungan itu, jika
fortune
akan melaporkan ralat secara bertulis kepada saluran tertutup dalam status, kemudian output|| echo "ΠΡΠΈΠ±ΠΊΠ°"
ia tidak akan sampai ke mana-mana, kerana saluran itu sudah ditutup. -
fortune | cat - | head -1 && echo "Π£ΡΠΏΠ΅ΡΠ½ΠΎ" || echo "ΠΡΠΈΠ±ΠΊΠ°"
Inilah utilitinya
cat
bertindak sebagai peredam kerana ia mengabaikan ralatEPIPE
apabila ditarik balik. Ini cukup buat kesimpulan sekarangfortune
kecil (beberapa baris) dan muat dalam penimbal saluran (daripada 512 bait hingga β64K, dalam kebanyakan OS β₯4K). Jika tidak masalah mungkin kembali.
Cara memproses dengan betul EPIPE
dan ralat rakaman lain?
Tiada penyelesaian tunggal yang betul, tetapi terdapat cadangan mudah:
EPIPE
diperlukan mesti diproses (dan ditunjukkan dalam status keluar) apabila mengeluarkan data yang memerlukan integriti. Contohnya, semasa operasi pengarkib atau utiliti sandaran.EPIPE
lebih baik abaikan apabila memaparkan maklumat dan mesej tambahan. Contohnya, apabila memaparkan maklumat tentang pilihan--help
atau--version
.- Jika kod yang dibangunkan boleh digunakan dalam saluran paip sebelum ini
| head
, KemudianEPIPE
Adalah lebih baik untuk mengabaikan, jika tidak, lebih baik memproses dan mencerminkan dalam status keluar.
Saya ingin mengambil kesempatan ini untuk mengucapkan terima kasih kepada pasukan
Keep it up Rakan-rakan, naik
Terima kasih
KDPV daripada
Sumber: www.habr.com