Бас нэг Хэйзенбуг матрын дэргэдүүр өнгөрөв

Бас нэг Хэйзенбуг матрын дэргэдүүр өнгөрөв

$> set -o pipefail

$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!

$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проиграли

энд fortune нөхцөлт хөтөлбөргүйгээр exit(rand()).

Чи тайлбарлаж чадах уу? энд юу болоод байна?

Уянгын-түүхийн ухралт

Би энэ Хэйзенбугтай дөрөвний нэг зууны өмнө анх танилцсан. Дараа нь FaxNET-ийн гарцын хувьд хэд хэдэн хэрэгслүүдээр дамжуулан үүсгэх шаардлагатай болсон хоолой FreeBSD дор "даам тоглох". Би өөрийгөө дэвшилтэт, нэлээд туршлагатай програмист гэж бодож байсан. Тиймээс би бүх зүйлийг аль болох болгоомжтой, болгоомжтой хийх, алдаа засахад онцгой анхаарал хандуулахыг зорьсон ...

Өмнө нь sendmail болон uucp/uupc-ийн алдаатай харьцаж байсан туршлага маань "алдааг нарийн зохицуулах" хичээл зүтгэлийг минь нэмэгдүүлсэн. Тэр түүхийн нарийн ширийн зүйлд шумбах нь утгагүй ч би энэ Хэйзенбугтай хоёр долоо хоног 10-14 цаг ноцолдсон. Тиймээс санасандаа хүрч, өчигдөр энэ хуучин танил маань дахин зочилжээ.

TL; DR Хариулт

Хэрэгсэл head болно сувгийг хаах fortune тэр дор нь тэр эхний мөрийг уншсан даруйдаа. Хэрэв fortune нэгээс олон мөр, дараа нь харгалзах дуудлагыг гаргана write() алдаа буцаах эсвэл хүссэнээс цөөн байт гарсныг мэдээлэх болно. Хариуд нь алдаатай болгоомжтой бичсэн fortune энэ байдлыг өөрийн гарах байдалд тусгах эрхтэй. Дараа нь суулгацын улмаас set -o pipefail ажиллана || echo "Вы проиграли".

Гэсэн хэдий ч, head цагтаа амжихгүй байж магадгүй өмнө хаах fortune өгөгдлийг гаргаж дуусгах болно. Дараа нь ажиллах болно && echo "Повезло!".

Миний өнөөдрийн нэгэнд GNUMakefile ийм байдаг хэлтэрхий:

echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'

Хүнээр орчуулсан

Энэ нь энд нийтлэг байдаг GNU хийх и bash сонголтыг ашиглан хөрвүүлэгчийн аргаар --version Энэ нь түүнийг хэн болохыг асууж, хэрэв энэ сонголтыг дэмжихгүй бол stub оруулна "GCC эсвэл CLANG нийцтэй хөрвүүлэгчийг ашиглана уу".

Дуртай бойлер хавтан хаанаас ч олж болно. Энэ нь эрт дээр үеэс энэ газарт гарч ирсэн бөгөөд хаа сайгүй төгс ажиллаж байсан (Linux, Solaris, OSX, FreeBSD, WSL гэх мэт). Харин өчигдөр altlinux тавцан дээр Эльбрус 2000 (E2K) Би анзаарсан:

#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"

Үнэнийг хэлэхэд, би хуучин "танилаа" шууд таньсангүй. Түүгээр ч зогсохгүй уг төслийг Эльбрус дээр олон удаа туршиж үзсэн бөгөөд Alt зэрэг олон янзын хуваарилалтад хамрагдсан. Төрөл бүрийн хөрвүүлэгч, GNU Make болон bash хувилбаруудтай. Тиймээс би энд өөрийнхөө алдааг харахыг хүсээгүй.

Асуудлыг дахин гаргах эсвэл юу болж байгааг ойлгохыг оролдох үед илүү хачирхалтай зүйлс тохиолдож эхлэв.
Тушаалын мөрийн үсэг:

echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"

Хааяа нэг нэмэлт текст гаргана, тэгвэл үгүй... Ихэнхдээ сонголтуудын аль нэг нь нэлээд удаан наалддаг, гэхдээ та удаан нударвал хоёуланг нь авах болно!

Мэдээжийн хэрэг, strace бидний бүх зүйл! Тэгээд strace tirade бичээд Enter дарж амжаагүй байтал би хуучин найз ноён Хайзенбуг болон хөгжүүлэгчидтэй танилцлаа. хөрвүүлэгч Би 25 жилийн өмнө Дурсамж… Тэгээд гунигтай байж энэ тэмдэглэлийг бичихээр шийдлээ 😉

Дашрамд хэлэхэд, ямар ч өөрийгөө хүндэтгэдэг шиг Хэйзенбуг, доор strace үржихгүй байхыг илүүд үздэг.

Тэгэхээр юу болоод байна?

  • Хэрэгсэл head хүссэн тооны мөрийг уншмагцаа уншиж байгаа сувгийг хаах эрхтэй (эсвэл бүр албаддаг).
  • Өгөгдөл үүсгэх програм зохиогч (энэ тохиолдолд cc) болно олон мөр хэвлэх ба үнэгүй Үүнийг олон дуудлагаар хийх write().
  • бол Уншигч зохиолчийн талын бичлэг дуусахаас өмнө сувгаа хаах цаг гарвал зохиолч алдаа гаргана.
  • Зохиолч програм эрхтэй хоёулаа суваг бичих алдааг үл тоомсорлож, дуусгах коддоо тусгана.
  • Суурилуулалтын улмаас set -o pipefail Хэрэв үр дүн нь дор хаяж нэг элементээс тэг биш байвал дамжуулах хоолойн дуусгах код нь тэг биш (алдаатай) байх бөгөөд дараа нь ажиллах болно. || echo "Please use GCC or CLANG compatible compiler".

Зохиогчийн программ дохиогоор хэрхэн ажиллахаас хамаарч өөр өөр байж болно. Жишээлбэл, програм хэвийн бусаар дуусгавар болох (тэг биш/алдаа дуусгавар болгох төлөвийг автоматаар үүсгэх) эсвэл write() хүссэн ба тохируулснаас цөөн байт бичсэний үр дүнг буцаана errno = EPIPE.

Хэн буруутгах вэ?

Тодорхойлсон тохиолдолд бүх зүйлээс бага зэрэг. Харьцахад алдаа гарлаа cc (lcc:1.23.20:Sep—4-2019:e2k-v3-linux) биш илүүдэл. Ихэнх тохиолдолд болгоомжтой байхын тулд алдаа гаргах нь дээр, гэхдээ энэ нь уламжлалт зан үйлд зориулагдсан уурын зуухны гэнэтийн дутагдлыг илрүүлдэг.

Би яах ёстой вэ?

Буруу:

fortune | head -1 && echo "Повезло, но вы рискуете!" || echo "WTF?"

Зөв:

  1. (fortune && echo "Успешно" || echo "Ошибка") | head -1

    Энд хоолойг эрт хаахыг үүрлэсэн дамжуулах хоолойд ("хашилтанд") засвар үйлчилгээ хийх үед командын орчуулагч хариуцна. Үүний дагуу хэрэв fortune статусын хаалттай суваг руу бичих алдааг мэдээлэх болно, дараа нь гаралт || echo "Ошибка" Энэ суваг аль хэдийн хаагдсан тул хаашаа ч хүрэхгүй.

  2. fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"

    Хэрэгсэл нь энд байна cat алдааг үл тоомсорлодог тул сааруулагчийн үүрэг гүйцэтгэдэг EPIPE татан буулгах үед. Энэ нь одоо дүгнэлт хийхэд хангалттай fortune жижиг (хэд хэдэн мөр) ба сувгийн буферт (512 байтаас ≈64К хүртэл, ихэнх үйлдлийн системд ≥4K) багтдаг. Үгүй бол асуудал буцаж болзошгүй.

Хэрхэн зөв боловсруулах вэ EPIPE болон бусад бичлэгийн алдаа?

Ганц зөв шийдэл байхгүй, гэхдээ энгийн зөвлөмжүүд байдаг:

  • EPIPE шаардлагатай боловсруулах ёстой (мөн гарах төлөвт тусгагдсан) бүрэн бүтэн байдлыг шаарддаг өгөгдлийг гаргах үед. Жишээлбэл, архивлагч эсвэл нөөцлөх хэрэгслийг ажиллуулах явцад.
  • EPIPE үл тоомсорлох нь дээр мэдээлэл болон туслах мессежийг харуулах үед. Жишээлбэл, сонголтуудын талаархи мэдээллийг харуулах үед --help буюу --version.
  • Хэрэв боловсруулж буй кодыг өмнө нь дамжуулах хоолойд ашиглаж болно | headДараа нь EPIPE Үүнийг үл тоомсорлох нь дээр, эс тэгвээс гарах төлөвийг боловсруулж, тусгах нь дээр.

Энэ завшааныг ашиглаад багуудад баярласнаа илэрхийлмээр байна MCST и altlinux их бүтээмжтэй ажлын төлөө. Таны шийдэмгий байдал үнэхээр гайхалтай!
Цаашдаа үргэлжлүүлээрэй Камарадууд, дээшээ намрын уулзалтууд!

Спасибо Берез үсгийн алдаа, алдааг засах зориулалттай.
KDPV-аас Георгий А.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх