$> set -o pipefail
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проиграли
Hér fortune
skilyrt forrit án exit(rand())
.
Geturðu útskýrt? hvað er að hérna?
Ljóðsögulegur útrás
Þessum Heisenbug kynntist ég fyrst fyrir aldarfjórðungi. Síðan fyrir gáttina í FaxNET var nauðsynlegt að búa til nokkur tól í gegnum
Fyrri reynsla mín af því að takast á við villur í sendmail og uucp/uupc jók kostgæfni mína við „rækilega villumeðferð“. Það þýðir ekkert að kafa ofan í smáatriði þeirrar sögu, en ég barðist við þessa Heisenbug í tvær vikur í 10-14 tíma. Þess vegna var þess minnst og í gær kíkti þessi gamli kunningi við í heimsókn aftur.
TL;DR svar
Gagnsemi head
getur loka rásinni frá fortune
í einu um leið og hann les fyrstu línuna. Ef fortune
gefur út fleiri en eina línu, síðan samsvarandi símtal write()
mun skila villu eða tilkynna að færri bæti séu framleidd en beðið var um. Aftur á móti skrifað með varkárri villumeðferð fortune
hefur rétt til að endurspegla þessa stöðu í útgöngustöðu sinni. Þá vegna uppsetningar set -o pipefail
mun virka || echo "Вы проиграли"
.
Hins vegar, head
kemst kannski ekki í tæka tíð loka áður fortune
mun klára að gefa út gögn. Þá mun það virka && echo "Повезло!"
.
Í einum af mínum í dag GNUMakefile
echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'
Þýtt á mannlegt
Það er algengt hér fyrir --version
það spyr hver hann sé, og ef valmöguleikinn er ekki studdur, þá er stubbur settur inn "Vinsamlegast notaðu GCC eða CLANG samhæfðan þýðanda".
Svipað
#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"
Satt að segja þekkti ég ekki gamla „kunningja“ minn strax. Þar að auki hefur verkefnið þegar verið prófað margsinnis á Elbrus og undir mörgum mismunandi dreifingum, þar á meðal Alt. Með ýmsum þýðendum, útgáfum af GNU Make og bash. Þess vegna vildi ég ekki sjá mistök mín hér.
Þegar reynt var að endurskapa vandamálið og/eða skilja hvað var í gangi fóru skrýtnari hlutir að gerast.
Skipanalínustafur:
echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"
Öðru hvoru myndi það framleiða aukatexta, svo ekki... Oft myndi einn af valmöguleikunum standa í ansi langan tíma, en ef þú potaðir lengur, fékkstu alltaf báða!
Auðvitað, strace
Við the vegur, eins og allir sjálfsvirðingar strace
vill helst ekki fjölga sér.
Svo hvað er í gangi?
- Gagnsemi
head
hefur rétt (eða réttara sagt, er jafnvel neyddur) til að loka rásinni sem verið er að lesa um leið og hún les umbeðinn fjölda lína. - Gagnaframleiðandi forritsritari (í þessu tilfelli
cc
) getur prenta margar línur og ókeypis Gerðu þetta með mörgum símtölumwrite()
. - Ef lesandinn mun hafa tíma til að loka rásinni hjá sér áður en upptöku lýkur hjá rithöfundinum, þá mun rithöfundurinn fá villu.
- Rithöfundaforrit rétt á bæði hunsa rásarvilluna og endurspegla hana í útfyllingarkóðanum þínum.
- Vegna uppsetningar
set -o pipefail
leiðslulokunarkóði verður ekki núll (rangur) ef niðurstaðan er ekki núll úr að minnsta kosti einum þætti, og þá mun það virka|| echo "Please use GCC or CLANG compatible compiler"
.
Það geta verið afbrigði eftir því hvernig ritunarforritið virkar með merkjum. Til dæmis getur forritið hætt óeðlilega (með sjálfvirkri myndun á stöðvunarstöðu sem er ekki núll/villu), eða write()
mun skila niðurstöðu um að skrifa færri bæti en beðið var um og stillt errno = EPIPE
.
Hver er sekur?
Í því tilviki sem lýst er lítið af öllu. Villa meðhöndlun í cc
(lcc:1.23.20:Sep—4-2019:e2k-v3-linux) er ekki óþarfi. Í mörgum tilfellum er betra að skipta sér af varkárni, þó að það afhjúpi skyndilega galla í ketilplötu sem er hannaður fyrir hefðbundna hegðun.
Hvað á að gera?
Rangt:
fortune | head -1 && echo "Повезло, но вы рискуете!" || echo "WTF?"
Rétt:
-
(fortune && echo "Успешно" || echo "Ошибка") | head -1
Hér mun snemmbúin lokun á pípu vera meðhöndluð af skipanatúlknum við þjónustu við hreiðri leiðslu ("innan" sviga). Í samræmi við það, ef
fortune
mun tilkynna skriflega villu til lokaðrar rásar í stöðunni, síðan úttakið|| echo "Ошибка"
það kemst hvergi þar sem rásin er þegar lokuð. -
fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"
Hér er gagnsemin
cat
virkar sem dempara því það hunsar villunaEPIPE
við afturköllun. Þetta er nóg fyrir niðurstöðu núnafortune
lítill (nokkrar línur) og passar í biðminni rásarinnar (frá 512 bætum til ≈64K, í flestum stýrikerfum ≥4K). Annars gæti vandamálið komið aftur.
Hvernig á að vinna rétt EPIPE
og aðrar upptökuvillur?
Það er engin ein rétt lausn, en það eru einfaldar ráðleggingar:
EPIPE
krafist verður að afgreiða (og endurspeglast í útgöngustöðunni) þegar þú sendir út gögn sem krefjast heiðarleika. Til dæmis meðan á rekstri skjalavörslu eða öryggisafrita stendur.EPIPE
betra að hunsa þegar birtar eru upplýsingar og aukaskilaboð. Til dæmis þegar birtar eru upplýsingar um valkosti--help
eða--version
.- Ef kóðann sem verið er að þróa er hægt að nota í leiðslu áður
| head
þáEPIPE
Það er betra að hunsa, annars er betra að vinna úr og endurspegla í útgöngustöðunni.
Ég vil nota tækifærið til að koma á framfæri þakklæti til liðanna
Haltu áfram Camarades, upp
Takk
KDPV frá
Heimild: www.habr.com