$> set -o pipefail
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Повезло!
$> fortune | head -1 > /dev/null && echo "Повезло!" || echo "Вы проиграли"
Вы проиграли
Itt fortune
feltételes program nélkül exit(rand())
.
Meg tudod magyarázni? mi a baj itt?
Lírai-történeti kitérő
Ezzel a Heisenbuggal negyedszázaddal ezelőtt ismerkedtem meg először. Ezután a FaxNET-ben lévő átjáróhoz több segédprogramot kellett létrehozni ezen keresztül
A sendmail és az uucp/uupc hibáinak kezelésével kapcsolatos korábbi tapasztalataim növelték az „alapos hibakezelés” terén végzett szorgalmamat. Nincs értelme belemerülni a történet részleteibe, de két hétig 10-14 órán keresztül küzdöttem ezzel a Heisenbug-gal. Ezért emlékeztek rá, és tegnap ez a régi ismerős ismét beugrott, hogy meglátogassa.
TL;DR Válasz
Hasznosság head
képes zárja be a csatornát fortune
сразу amint elolvassa az első sort. Ha fortune
egynél több sort ad ki, majd a megfelelő hívást write()
hibát ad vissza, vagy azt jelenti, hogy a kértnél kevesebb bájt kerül kiadásra. Viszont gondos hibakezeléssel írva fortune
jogában áll ezt a helyzetet a kilépési státuszában tükrözni. Aztán telepítés miatt set -o pipefail
működni fog || echo "Вы проиграли"
.
Azonban, head
lehet, hogy nem ér rá időben előtt zárja be fortune
befejezi az adatok kiadását. Akkor menni fog && echo "Повезло!"
.
Az egyik mai napon GNUMakefile
echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'
Emberre lefordítva
Ez gyakori itt azért --version
megkérdezi, hogy ki ő, és ha az opció nem támogatott, akkor beszúr egy csonkot "Kérjük, használjon GCC vagy CLANG kompatibilis fordítót".
mint
#define MDBX_BUILD_COMPILER "lcc:1.23.20:Sep--4-2019:e2k-v3-linux Please use GCC or CLANG compatible compiler"
Őszintén szólva, nem ismertem fel azonnal régi „ismerősömet”. Sőt, a projektet már sokszor tesztelték Elbruson és számos különféle disztribúció alatt, beleértve az Alt-ot is. Különféle fordítókkal, a GNU Make és a bash verzióival. Ezért nem akartam itt látni a hibámat.
Amikor megpróbáltuk reprodukálni a problémát és/vagy megérteni, hogy mi történik, furcsább dolgok kezdtek történni.
Parancssori varázslat:
echo "#define MDBX_BUILD_COMPILER '$(set -o pipefail; LC_ALL=C cc --version | head -1 || echo "Please use GCC or CLANG compatible compiler")'"
Időnként plusz szöveget produkált, aztán nem... Sokszor az egyik opció elég sokáig kitartott, de ha hosszabban piszkáltál, mindig megkaptad mindkettőt!
Természetesen, strace
Mellesleg, mint minden önbecsülő strace
inkább nem szaporodik.
Nos, miújság?
- Hasznosság
head
joga van (vagy inkább kénytelen) bezárni az olvasott csatornát, amint az beolvassa a kívánt számú sort. - Az adatgeneráló programíró (ebben az esetben
cc
) képes több sort nyomtatni és ingyenes ezt több hívás útján teheti megwrite()
. - Ha az olvasónak lesz ideje bezárni a csatornát az oldalán, mielőtt az írói oldalon a felvétel vége, akkor az író hibaüzenetet kap.
- Írói program jogosult mindkettő figyelmen kívül hagyja a csatornaírási hibát, és tükrözi azt a befejezési kódban.
- Beépítés miatt
set -o pipefail
a folyamat befejezési kódja nem nulla (hibás), ha az eredmény legalább egy elemből nem nulla, és akkor működik|| echo "Please use GCC or CLANG compatible compiler"
.
Eltérések lehetnek attól függően, hogy az íróprogram hogyan működik a jelekkel. Például előfordulhat, hogy a program rendellenesen leáll (nem nulla/hiba leállási állapot automatikus generálásával), vagy write()
a kértnél és beállítottnál kevesebb bájt írásának eredményét adja vissza errno = EPIPE
.
Ki a hibás?
A leírt esetben egy kicsit mindenből. Hiba a kezelés során cc
(lcc:1.23.20:Sep—4-2019:e2k-v3-linux) nem redundáns. Sok esetben jobb az óvatosság mellett tévedni, bár ez felfedi a hagyományos viselkedésre tervezett kazánok hirtelen hibáit.
Mit kell tenni?
Rossz:
fortune | head -1 && echo "Повезло, но вы рискуете!" || echo "WTF?"
korrigálni:
-
(fortune && echo "Успешно" || echo "Ошибка") | head -1
Itt a cső korai zárását a parancsértelmező kezeli a beágyazott folyamat kiszolgálása során (a zárójelben "belül"). Ennek megfelelően, ha
fortune
írási hibát jelez egy zárt csatornának az állapotában, majd a kimeneten|| echo "Ошибка"
nem jut sehova, mivel a csatorna már bezárt. -
fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"
Itt van a segédprogram
cat
csillapítóként működik, mert figyelmen kívül hagyja a hibátEPIPE
visszavonáskor. Ez most elég a következtetéshezfortune
kicsi (több sor), és elfér a csatornapufferben (512 bájttól ≈64K-ig, a legtöbb operációs rendszerben ≥4K). Ellenkező esetben a probléma visszatérhet.
Hogyan kell helyesen feldolgozni EPIPE
és egyéb felvételi hibák?
Nincs egyetlen helyes megoldás, de vannak egyszerű ajánlások:
EPIPE
kötelező fel kell dolgozni (és tükröződik a kilépési állapotban) az integritást igénylő adatok kiadásakor. Például archiválók vagy biztonsági mentési segédprogramok működése közben.EPIPE
jobb figyelmen kívül hagyni információk és segédüzenetek megjelenítésekor. Például amikor információkat jelenít meg a lehetőségekről--help
vagy--version
.- Ha a fejlesztés alatt álló kód egy folyamatban használható korábban
| head
, AkkorEPIPE
Jobb figyelmen kívül hagyni, különben jobb feldolgozni és tükrözni a kilépési állapotot.
Szeretném megragadni az alkalmat, hogy kifejezzem hálámat a csapatoknak
Csak így tovább Camarades, csak így tovább
Köszönöm
KDPV innen
Forrás: will.com