$> set -o pipefail
$> fortune | head -1 > /dev/null && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ!" || echo "ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ"
ΠΠΎΠ²Π΅Π·Π»ΠΎ!
$> fortune | head -1 > /dev/null && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ!" || echo "ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ"
ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ
Dito fortune
kondisyonal na programa nang walang exit(rand())
.
Maaari mo bang ipaliwanag? anong meron dito?
Lyrical-historical digression
Una kong nakilala ang Heisenbug na ito isang-kapat ng isang siglo ang nakalipas. Pagkatapos ay para sa gateway sa FaxNET kinakailangan na lumikha ng ilang mga utility sa pamamagitan ng
Ang dati kong karanasan sa pagharap sa mga bug sa sendmail at uucp/uupc ay nagdagdag sa aking kasipagan sa "masusing paghawak ng error." Walang punto sa pagsisid sa mga detalye ng kuwentong iyon, ngunit nahirapan ako sa Heisenbug na ito sa loob ng dalawang linggo sa loob ng 10-14 na oras. Samakatuwid, ito ay naalala, at kahapon ang matandang kakilala na ito ay dumaan upang bisitahin muli.
Sagot ng TL;DR
Kagamitan head
maaari isara ang channel mula sa fortune
ΡΡΠ°Π·Ρ pagkabasa niya sa unang linya. Kung fortune
naglalabas ng higit sa isang linya, pagkatapos ay ang kaukulang tawag write()
ay magbabalik ng isang error o ulat na mas kaunting mga byte ang output kaysa sa hiniling. Sa turn, nakasulat na may maingat na paghawak ng error fortune
ay may karapatang ipakita ang sitwasyong ito sa katayuan ng paglabas nito. Pagkatapos ay dahil sa pag-install set -o pipefail
magtatrabaho || echo "ΠΡ ΠΏΡΠΎΠΈΠ³ΡΠ°Π»ΠΈ"
.
Gayunpaman, head
maaaring hindi maabot sa oras malapit na kanina fortune
matatapos ang pag-output ng data. Pagkatapos ito ay gagana && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ!"
.
Sa isa sa aking ngayon GNUMakefile
echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'
Isinalin sa tao
Ito ay karaniwan dito para sa --version
ito ay nagtatanong kung sino siya, at kung ang opsyon ay hindi suportado, pagkatapos ay isang stub ay ipinasok "Pakigamit ang GCC o CLANG compatible compiler".
katulad
#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"
Sa totoo lang, hindi ko agad nakilala ang dati kong "kakilala." Bukod dito, ang proyekto ay nasubok nang maraming beses sa Elbrus at sa ilalim ng maraming iba't ibang mga pamamahagi, kabilang ang Alt. Sa iba't ibang compiler, bersyon ng GNU Make at bash. Samakatuwid, hindi ko nais na makita ang aking pagkakamali dito.
Kapag sinusubukang i-reproduce ang problema at/o unawain kung ano ang nangyayari, mas maraming kakaibang bagay ang nagsimulang mangyari.
Spell ng command line:
echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"
Paminsan-minsan ay gagawa ito ng dagdag na text, pagkatapos ay hindi... Kadalasan ang isa sa mga opsyon ay mananatili nang medyo matagal, ngunit kung sumundot ka nang mas mahaba, palagi mong makukuha ang pareho!
Siyempre, strace
Sa pamamagitan ng paraan, tulad ng anumang paggalang sa sarili strace
mas pinipiling hindi magparami.
Kaya ano ang nangyayari?
- Kagamitan
head
ay may karapatan (o sa halip, napipilitan pa nga) na isara ang channel na binabasa sa sandaling mabasa nito ang hiniling na bilang ng mga linya. - Ang data-generating program-writer (sa kasong ito
cc
) maaari mag-print ng maraming linya at libre gawin ito sa pamamagitan ng maraming tawagwrite()
. - Kung magkakaroon ng oras ang mambabasa na isara ang channel sa kanyang panig bago matapos ang pag-record sa panig ng manunulat, pagkatapos ay makakatanggap ng error ang manunulat.
- Programa ng manunulat ay may tama parehong binabalewala ang channel write error at ipinapakita ito sa iyong completion code.
- Dahil sa pag-install
set -o pipefail
ang code ng pagkumpleto ng pipeline ay magiging non-zero (mali) kung ang resulta ay hindi zero mula sa hindi bababa sa isang elemento, at pagkatapos ay gagana ito|| echo "Please use GCC or CLANG compatible compiler"
.
Maaaring may mga pagkakaiba-iba depende sa kung paano gumagana ang programa ng manunulat sa mga signal. Halimbawa, ang programa ay maaaring magwakas nang hindi normal (na may awtomatikong pagbuo ng isang hindi zero/error termination status), o write()
ibabalik ang resulta ng pagsulat ng mas kaunting mga byte kaysa sa hiniling at itinakda errno = EPIPE
.
Sino ang sisihin?
Sa inilarawang kaso kaunti sa lahat. Error sa paghawak cc
(lcc:1.23.20:Sepβ4-2019:e2k-v3-linux) ay hindi kalabisan. Sa maraming mga kaso, mas mabuting magkamali sa panig ng pag-iingat, bagama't ito ay naglalantad ng mga biglaang pagkukulang sa isang boilerplate na idinisenyo para sa tradisyonal na pag-uugali.
Ano ang dapat gawin?
Maling:
fortune | head -1 && echo "ΠΠΎΠ²Π΅Π·Π»ΠΎ, Π½ΠΎ Π²Ρ ΡΠΈΡΠΊΡΠ΅ΡΠ΅!" || echo "WTF?"
Tamang:
-
(fortune && echo "Π£ΡΠΏΠ΅ΡΠ½ΠΎ" || echo "ΠΡΠΈΠ±ΠΊΠ°") | head -1
Dito, ang maagang pagsasara ng pipe ay hahawakan ng command interpreter kapag sineserbisyuhan ang nested pipeline ("sa loob" ng mga panaklong). Alinsunod dito, kung
fortune
ay mag-uulat ng error sa pagsulat sa isang saradong channel sa status, pagkatapos ay ang output|| echo "ΠΡΠΈΠ±ΠΊΠ°"
hindi ito makakarating kahit saan, dahil sarado na ang channel. -
fortune | cat - | head -1 && echo "Π£ΡΠΏΠ΅ΡΠ½ΠΎ" || echo "ΠΡΠΈΠ±ΠΊΠ°"
Narito ang utility
cat
gumaganap bilang isang damper dahil binabalewala nito ang errorEPIPE
sa pag-withdraw. Ito ay sapat na para sa ngayon konklusyonfortune
maliit (ilang linya) at akma sa buffer ng channel (mula 512 bytes hanggang β64K, sa karamihan ng OS β₯4K). Kung hindi, maaaring bumalik ang problema.
Paano magproseso ng tama EPIPE
at iba pang mga error sa pag-record?
Walang iisang tamang solusyon, ngunit may mga simpleng rekomendasyon:
EPIPE
kinakailangan dapat iproseso (at makikita sa exit status) kapag naglalabas ng data na nangangailangan ng integridad. Halimbawa, sa panahon ng pagpapatakbo ng mga archiver o backup na kagamitan.EPIPE
mas mabuting huwag pansinin kapag nagpapakita ng impormasyon at mga pantulong na mensahe. Halimbawa, kapag nagpapakita ng impormasyon sa mga opsyon--help
o--version
.- Kung ang code na binuo ay maaaring gamitin sa isang pipeline bago
| head
, PagkataposEPIPE
Ito ay mas mahusay na huwag pansinin, kung hindi, ito ay mas mahusay na iproseso at sumasalamin sa exit status.
Gusto kong samantalahin ang pagkakataong ito upang ipahayag ang aking pasasalamat sa mga koponan
Keep it up Camarades, up
salamat
KDPV mula sa
Pinagmulan: www.habr.com