$> set -o pipefail
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проиграли
اهو آهي fortune
بغير مشروط پروگرام exit(rand())
.
ڇا توھان وضاحت ڪري سگھو ٿا؟ هتي ڇا غلط آهي?
شعري-تاريخي تحرڪ
مان پهريون ڀيرو هن هيزن بگ سان هڪ چوٿون صدي اڳ واقف ٿيس. پوءِ FaxNET ۾ گيٽ وي لاءِ ان جي ذريعي ڪيترن ئي افاديت کي ٺاهڻ ضروري هو
منھنجو اڳوڻو تجربو موڪلڻ واري ميل ۽ uucp/uupc ۾ بگ سان معاملو ڪرڻ جو "مڪمل غلطي سنڀالڻ" ۾ منھنجي محنت ۾ اضافو ٿيو. ان ڪهاڻي جي تفصيلن ۾ ڊائيونگ ڪرڻ جو ڪو به مطلب ناهي، پر مون هن Heisenbug سان ٻن هفتن تائين 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')"'
انسان ۾ ترجمو ڪيو ويو
اهو هتي لاء عام آهي --version
اهو پڇي ٿو ته هو ڪير آهي، ۽ جيڪڏهن آپشن سپورٽ نه آهي، پوء هڪ اسٽب داخل ڪيو ويو آهي "مهرباني ڪري استعمال ڪريو GCC يا CLANG مطابقت رکندڙ مرتب ڪندڙ".
پسند ڪريو
#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"
سچ پچ، مون کي فوري طور تي منهنجي پراڻي "واقف" کي سڃاڻي نه سگهيو. ان کان علاوه، پروجيڪٽ اڳ ۾ ئي ايلبرس تي ڪيترائي ڀيرا آزمايا ويا آهن ۽ ڪيترن ئي مختلف تقسيم جي تحت، Alt سميت. مختلف گڏ ڪرڻ وارن سان، GNU ميڪ ۽ بيش جا ورجن. ان ڪري، مان هتي پنهنجي غلطي ڏسڻ نه ٿي چاهيان.
جڏهن مسئلو ٻيهر پيدا ڪرڻ جي ڪوشش ڪئي وئي ۽ / يا سمجهي رهيو هو ته ڇا ٿي رهيو آهي، وڌيڪ عجيب شيون ٿيڻ شروع ٿي.
ڪمانڊ لائن اسپيل:
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
ٻيهر پيدا ڪرڻ کي ترجيح نه ڏيندو.
پوءِ ڇا پيو ٿئي؟
- افاديت
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?"
صحيح طور تي
-
(fortune && echo "Успешно" || echo "Ошибка") | head -1
هتي، پائپ جي شروعاتي بندش کي ڪمانڊ مترجم طرفان سنڀاليو ويندو جڏهن نيسٽ ٿيل پائپ لائن ("اندر" قوس جي خدمت ڪندي). مطابق، جيڪڏهن
fortune
اسٽيٽس ۾ بند چينل تي لکڻ ۾ غلطي جي رپورٽ ڪندو، پوءِ ٻاھر|| echo "Ошибка"
اهو ڪٿي به نه ملندو، ڇو ته چينل اڳ ۾ ئي بند آهي. -
fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"
هتي جي افاديت آهي
cat
damper طور ڪم ڪري ٿو ڇاڪاڻ ته اهو غلطي کي نظر انداز ڪري ٿوEPIPE
واپسي تي. ھاڻي نتيجي لاءِ اھو ئي ڪافي آھيfortune
ننڍيون (ڪيترائي لائينون) ۽ چينل بفر ۾ فٽ ٿين ٿيون (512 بائيٽ کان ≈64K تائين، اڪثر OS ≥4K ۾). ٻي صورت ۾ مسئلو واپس ٿي سگهي ٿو.
صحيح طريقي سان ڪيئن عمل ڪجي EPIPE
۽ ٻيون رڪارڊنگ غلطيون؟
ڪو به واحد صحيح حل ناهي، پر هتي سادي سفارشون آهن:
EPIPE
گھربل عمل ٿيڻ گهرجي (۽ نڪرڻ واري حالت ۾ ظاهر ٿئي ٿو) جڏهن ڊيٽا کي ٻاھر ڪڍيو وڃي ٿو جيڪو سالميت جي ضرورت آھي. مثال طور، آرڪائيورز يا بيڪ اپ افاديت جي آپريشن دوران.EPIPE
نظر انداز ڪرڻ بهتر آهي جڏهن معلومات ۽ معاون پيغام ڏيکاريندي. مثال طور، جڏهن اختيارن تي معلومات ڏيکاري ٿي--help
يا--version
.- جيڪڏهن ڪوڊ ترقي ڪئي پئي وڃي ته اڳ ۾ هڪ پائيپ لائين ۾ استعمال ڪري سگهجي ٿو
| head
، پوءEPIPE
اهو نظر انداز ڪرڻ بهتر آهي، ٻي صورت ۾ اهو بهتر آهي ته عمل ڪرڻ ۽ ٻاهر نڪرڻ واري حالت ۾ ڌيان ڏيڻ.
مان هن موقعي تي ٽيمن جي مهرباني جو اظهار ڪرڻ چاهيان ٿو
ڪيمريڊس، مٿي رکو
Спасибо
KDPV کان
جو ذريعو: www.habr.com