
$> 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 "Повезло!".
Во еден од моите денес има еден :
echo '#define MDBX_BUILD_COMPILER "$(shell set -o pipefail; $(CC) --version | head -1 || echo 'Please use GCC or CLANG compatible compiler')"'Преведено на човечки
Тоа е вообичаено овде за и на компајлер начин користејќи ја опцијата --version прашува кој е тој, и ако опцијата не е поддржана, тогаш се става никулец „Ве молиме користете компајлер компатибилен со GCC или CLANG“.
како Можете да го најдете насекаде. Се појави на ова место одамна и работеше совршено насекаде (Linux, Соларис, OSX, FreeBSD, итн.). Но вчера во на платформата Забележав:
#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")'"Одвреме-навреме произведуваше дополнителен текст, а потоа не... Често една од опциите се држеше доста долго, но ако ѕиркате подолго, секогаш ги добивате двете!
Се разбира, наше се! И откако напишав тирада, но немајќи време да притиснете 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?"Правилно:
(fortune && echo "Успешно" || echo "Ошибка") | head -1Овде, предвременото затворање на цевката ќе го управува командниот преведувач при сервисирање на вгнездениот цевковод („во“ заградите). Според тоа, ако
fortuneќе пријави грешка во пишување на затворен канал во статусот, потоа излезот|| echo "Ошибка"нема да стигне никаде, бидејќи каналот е веќе затворен.fortune | cat - | head -1 && echo "Успешно" || echo "Ошибка"Еве ја алатката
catделува како амортизер бидејќи ја игнорира грешкатаEPIPEпри повлекување. Ова е доволно за сега заклучокfortuneмал (неколку линии) и се вклопува во баферот на каналот (од 512 бајти до ≈64K, во повеќето ОС ≥4K). Во спротивно проблемот може да се врати.
Како правилно да се обработи EPIPE и други грешки при снимање?
Не постои единствено вистинско решение, но постојат едноставни препораки:
EPIPEпотребни мора да се обработи (и се рефлектира во статусот на излез) кога се издаваат податоци за кои е потребен интегритет. На пример, за време на работата на архиватори или резервни комунални услуги.EPIPEподобро да се игнорира при прикажување на информации и помошни пораки. На пример, кога се прикажуваат информации за опциите--helpили--version.- Ако кодот што се развива може да се користи во цевковод претходно
| head, ПотоаEPIPEПодобро е да се игнорира, инаку е подобро да се обработи и да се одрази во статусот на излез.
Би сакал да ја искористам оваа прилика да изразам благодарност до тимовите и за одлична продуктивна работа. Вашата решителност е неверојатна!
Продолжете така Камаради, така !
Благодарение за корекција на печатни грешки и грешки.
КДПВ од
Извор: www.habr.com
