Скучен едноредов калкулатор в sed
Писането на скучни ръководства, както вярвах, се отразява негативно на склада на характера и затова тялото ми се съпротивлява на дисциплината възможно най-добре от време на време. И така, наскоро, впечатлен от разказите на Зощенко, които чух, реших да предам, доколкото мога, на страниците на Хабр стил и най-вече дух, който ми е много близък и който, струва ми се, не омаловажава стойността на изложената същност, а действа като катализатор и гарантира наличието на интелигентност у ценителя. Промених съответно темата и ето какво получих от нея. Sed, според някои привърженици, е непредсказуем език с кален, старозаветен синтаксис, с редакции в полетата, направени от Кирил и Методий собственоръчно. Винаги уважавам мненията на опонентите, но абсолютно не съм длъжен да ги споделям, затова реших за себе си, че sed е това, от което се нуждаете, за да получите бързо мазоли и да не бъдете бяла врана в дискусии, когато мистериозни знаци, различни от литералите на регулярните изрази, се появяват в редовете на sed кода.
Какви инструменти имам? Първият е bash (версия 4.3.42). Второто е sed (4.2.2). Съдейки по версиите, ако фантазирате малко, тогава можем да предположим, че нашите коне са започнали приблизително в една и съща епоха и вървят, макар и не главата до главата, но с разлика от не повече от половината корпус. Цялата тази доброта се намира в операционната система fedora 24 на моя компютър.
След като опресних паметта си и преминах през урока от emulek, открих, че sed има модификатор, който ви позволява да вградите команди на обвивката и да замените шаблона със стойността, върната от тази команда. Първата ми линия в тази област изглеждаше доста обнадеждаваща.
Всичко се получи и на изхода ме чакаше здрава четворка! Команда "s" (заместване)съвпада с шаблона/([0-9]+)([-+])([0-9]+)/и го замества с резултата от командата/expr ([0-9]+) ([-+]) ([0-9]+)/e. Опциите в тази команда са дефинирани в шаблона. Първият блок в скоби съвпада с\1, вторият\2и третият\3. Нека отидем по-далеч и да разширим функционалността, като добавим аритметични знаци "*%/".
И веднага получаваме синтактична грешка в изхода в командата "expr". Започваме да анализираме и разбираме, че в израза\2при заместване звездичката има специално значение и sed замества нейната стойност със собствена, тоест с празнота. Ще трябва да избегнем този символ, преди екипът на bash да го приеме в обращение. Пишем друга команда за заместване и променяме малко шаблона.
Отново между! Шедьовърът просто иска картината "отново двойка"! Тук въведохме друга команда за заместване. Ние предхождаме звездичката в първия шаблон с икона с обратна наклонена черта, за да лишим злодея от нейните супер способности, а в заменения ред не забравяйте да избягате от самата икона с обратна наклонена черта. В резултат на това тази част се разраства до такава ужасна гледка/\\\*/.
Също така във втория шаблон, а именно във вторите кръгли скоби, се добавя обратна наклонена черта и за да не ограждаме градината до символния клас[-+*%/\], дефиниран от квадратни скоби, заместваме квантора "+", който ни дава съвпадение по образец за низ от два знака "\*". Разбира се, беше възможно шаблонът да се дефинира по-точно, но в този контекст това е напълно достатъчно.
Bash е добър, защото почти всяко нещо, налично в него, може да се направи по няколко различни начина. Между другото, това е неговото очевидно объркване. За извършване на аритметични операции с цели числа е осигурена по-модерна форма на нотация и не обиждайте брадатите администратори, аз катона същата възраст като поколението Pepsi, ще се въоръжа с алтернативната конструкция "echo $(( ))" и ще оставя "expr" само в редовете например. Новата конструкция ни позволява да се отървем от част от кода и напълно да опростим програмата. Няма нужда да екранирате зъбното колело. Тъй като ще опростим кода, можем да въведем допълнителна функционалност, поддържайки нивото на сложност на приемливо ниво за начинаещ.
Следващата версия на нашата програма, с въвеждането на преходи, приема формата на реален код.
Имайте предвид, че изходът от програмата е добре познат сигнал за прекъсване, задействан чрез натискане на клавишни комбинацииCtrl+C.
Но нека да разгледаме как работи условният скок. Командата "t" се използва във връзка с командата "s" (заместване) и резултатът от последната е дали е направен скок или не. Ако първата (при наличието на няколко) команда "s" направи заместване в буфера, тогава се изпълнява условното разклоняване.
Има и команда "T", която се изпълнява, ако първата (ако са няколко) команда "s" е неуспешна.
Анализирахме работата на програмата с прехода по условие. Спрете кажете. И защо имаме нужда от условен преход тук, когато безусловен преход ще бъде напълно достатъчен. Нека заменим командата "t" с командата за безусловен скок "b". Тестване.
Въвеждаме данните според очакванията, но на изхода няма резултат! Къде сбъркахме, защото логично всичко трябва да работи по абсолютно същия начин? Нека се върнем и анализираме отново работата на програмата. Както винаги, всичко се оказа елементарно. Не взехме предвид един момент, инструкцията за условно разклоняване "t" се задейства и прехвърля изпълнението на програмата към етикета в случай, че възникне заместване в инструкцията "s".
Ситуацията изисква обяснение. Въвеждаме допълнително още две команди и една опция, които коригират ситуацията. След като запишем резултата от изчислението с командата "p", принудително ще отпечатаме съдържанието на буфера и преди да се върнем в началото на програмата, ще го изчистим с командата "d". Опцията "-n" обикновено работи в тандем с командата "p" и потиска автоматичния буферен печат. Имам чувството, че съм узряла след такива злополуки за няколко години и ако продължава така, бързо ще остарея и ще остана стара мома. Нямах представа, че ще е толкова скучно!
Въпреки че в началото си вирах носа като сляпо коте, което търси развитие на кода, в заключение той все пак придоби следната форма.
Сметнах за разточително да дефинирам пълноценен шаблон, който по същество не прави нищо, освен да предоставя възможност за въвеждане на командна обвивка с помощта на такава конструкция, и намалих шаблона до минимум/.*/, който по същество съответства на всеки низ. Намерих го за приемливо и дори си въобразих, че съм застрахован за милион долара срещу печатни грешки. Ако не сте толкова сигурни в себе си като мен, тогава можете да вмъкнете следния шаблон:s/^-?[0-9]+[-+%/*]\*?-?[0-9]+$/. Съветвам всички други блондинки като мен да не се притесняват, защото дори при грешка при въвеждане допълнителният буфер се актуализира със загуба на междинни резултати и такъв цикъл се нарича много просто - „започнете отначало“. Не е необходимо да рестартирате програмата в същото време, достатъчно е да започнете да въвеждате правилните данни.

В тази част на програмата не само опростих шаблона, но също така опростих самата формула за запис на операнд. Сега вмъкваме операндите не поотделно, а като един ред, един блок от данни, означен като&.Амперсандът, синоним на този символ, обозначаващ целия ред, е\0. В този блок от код, завършващ с точка и запетая, ние променяме стойностите на главния буфер на изчислената стойност чрез командата на обвивката. След точката и запетая имаме командата "h", която копира всичко в главния буфер във вторичния буфер. След това програмата показва съдържанието на основния буфер на екрана и отива в началото на цикъла, чакайки въвеждането на нов ред.
Сега знаем, че имаме първия операнд в буфера и въвеждаме само знака на аритметичната операция и втория операнд. Първата команда "s" открива, че има низ в главния буфер, който съответства на шаблона/^[-+/%*]\*?-?[0-9]+$/и след това действието се прехвърля към блока от команди, ограден във къдрави скоби. Втората команда в блока, "G", добавя нов ред "\n" в края на основния буфер и след това копира реда от допълнителния буфер. В резултат на това имаме два реда наведнъж в главния буфер, разделени със символ за прекъсване на реда. Първият е просто знакът на въведената операция, а вторият операнд.
Неправилният ред на операндите веднага привлича вниманието. За да коригираме това малко недоразумение, преди да добавим реда от допълнителния буфер към основния, ще използваме коляното под формата на командата "x", която ще размени главния буфер с допълнителния и след това след изпълнение на командата "G" всичко ще бъде в правилния ред. В резултат на това след изпълнение на две команди "x;G" ще имаме подобен ред1operand\nSIGN2operandв главния буфер. Прекъсването на реда в средата на израза се оказва излишно за нас. Нека го премахнем със следната команда за заместванеs/\n//. Е, и по-нататък, както е написано, контролът преминава към „броенетокола."
Hardcore conf в C++. Каним само професионалисти.