Shell scriptek – fontos ismeretek

Már nagyot haladtunk, hiszen tudjuk, hogy a bash, illetve a shell scriptek nem mások, mint egy sima felsorolás, ahol megadjuk a parancsértelemőnek sorban, hogy mit tegyen. Pont úgy, mintha egymásután mi írnánk be a terminálba. Ha most abbahagyod az olvasást, és csak ennyire használod a scriptelési lehetőséget, akkor is gyorsabban, kényelmesebben tudod elvégeztetni a géppel az ismétlődő, mechanikus munkákat. Ha pedig többre vágysz, akkor pár alapvető programozási ismeretet kell elsajátítani. Nem lesz sok, és alapvetően egyszerű szerkezeteket ismerünk meg. A mai részben kicsit kiterjesztünk az egymásutáni feladatokat ellátó elvet, azzal, hogy az egymásutániságot szabályozzuk. Bár nagyon egyszerűnek tűnik a végére, de sok helyen használhatjuk majd ezeket. Aki kicsit jártasabb a parancssori megoldásokban, annak ezek ismerősek lesznek, mert nem script specifikus megoldások, hanem a parancsértelmező részei. Így már teljesen biztos azaz állítás, hogy aki kicsit ismeri a parancssort, annak a scriptek sem lesznek idegenek!

Feladat háttérbe küldése shell scriptben

Ezt a megoldást az autostart-nál már használtuk, a parancs után egy & jelet írtunk, így a háttérben fog futni, és nem látjuk a terminálban. Mindenki ismeri a sleep parancsot, ami nem tesz mást, mint a megadott másodpercig várakozásra kényszeríti a parancsértelmezőt.

Terminálban indítsd el:

sleep 20

majd írd be, hogy echo Teszt. Láthatod, hogy nem azonnal, hanem amikor lefut a 20mp-es várakozás, akkor kapod meg a kiírást: Teszt.

Most a

sleep 20 &

gépeld be. Rögvest visszakapod a promtot, és dolgozhatsz tovább. Érdekes, de ezt hogyan használhatjuk fel a scriptekben? Ha van olyan program, ami futása hosszabb, akkor a “sima felsorolás” esetén a parancsértelmező megvárja a lefutását, majd csak azután lép a következő sorra. Ami nem mindig jó, hiszen több parancs is futhat egymással párhuzamosan. Így ha a

parancs1 &
parancs2 &
parancs3 &

felsorolást használod, akkor a parancsok háttérbe kerülnek és rögvest továbblép a következőre. Teszteljük le:

#! /usr/bin/bash

sleep 10
echo világ

Igencsak “komoly” scriptet futtasd le. Vár 10mp-et, hogy kiírja a echo-nak megadott szöveget. Majd írd át úgy, hogy sleep 10 & és futtasd le újra. A különbség egyértelmű.

Mikor nem jó az ilyen megoldás egy scriptben?

Ha a parancs1 olyan műveletet végez el, aminek az eredményét a második parancs elvárja. Ilyen lehet egy olyan nagyobb zip fájl letöltése, majd annak kitömörítésére írt script. Hiába küldöd a háttérbe a letöltést, és lép a kitömörítést megadó parancs2-re a scripted, nem lesz mit kitömöríteni. Logikus, csak sokszor nem gondoljuk át előre :).

Ami nem script téma, de hasznos lehetetlen

A parancssorban is van lehetőség egymásurán megadni több, egymást követő parancsot egyszerre. Ez nagyon jó példa:

apt-get update ; apt-get upgrade ; apt-get autoremove

Így megadott parancsok egymás után lefutnak, ha az első kész, akkor a második stb. következik. Majdnem script 🙂 A fenti sor egy debian alapú Linux disztribúció adatbázis frissítési, rendszer frissítési és tisztítási parancsait írja le.

A fenti két megoldás kevésbé hasznos, illetve nagyobb odafigyelést kíván.

Eredmény szerinti parancs futtatás scriptben

Nem tudtam normálisabb alcímet kitalálni, de mindjárt érthető is lesz. Miért „kevésbé” hasznos az előbb leírt két megoldás? Mert nem ellenőrzi az előző parancs végrehajtását. Azaz ott nem használható, ahol fontos az előző parancs kifogástalan lefutása, hiba nélkülisége. A fenti példa akkor jó, ha 100%-ig biztosak vagyunk abban, hogy az adatbázis frissítés korrektül végrehajtható. Ha nem, akkor is lefut a upgrade, vagy legalábbis megpróbálja a csomagokat frissíteni. Így, ha azt szeretnénk, hogy csak akkor fusson a második, ha az előző hiba nélkül fut le, akkor ez nem lesz megfelelő. Ilyen esetben a && kell használni. Csak akkor hajtja végre a következőt, ha az előző rendben volt:

apt-get update && apt-get -y upgrade && apt-get autoremove

Azaz, ha ezt nem a parancssorban adod ki, hanem scriptben, akkor csak a „fejléc” és a formázás lesz más:

#! /usr/bin/bash

apt-get update &&
apt-get -y upgrade &&
apt-get autoremove

Ezzel az egyszerű módszerrel megakadályozhatod, hogy lefusson a következő parancs, ha az előző hibával lépett ki. Természetesen a hiba, hibajel stb. kezelésének van korrektebb módja is, de az már ennél bonyolultabb. Ha csak pár soros scriptet írsz, akkor ez megfelelő lesz. Fontos tudni, hogy ha az első parancs nem fut le, akkor a második sem, de semelyik sem, ami ezeket követi!

„Vagy” kötés a shell scriptben

Az || (két darab AltGr+W) operátor lehetővé teszi, hogy csak akkor hajtsa végre a második parancsot, ha az első parancs végrehajtása sikertelen, vagyis az első parancs kilépési állapota “1”. Azaz egy „vagy” kötést kap a két parancs. Ha az első nem jó, akkor jöhet a második.

A kipróbáláshoz sima felhasználóként:

#! /usr/bin/bash
apt-get update || echo „Te nem vagy ROOT!!!”

sort használhatod. Nyilván nem fut le az első, így a második lép érvénybe: kiírja a „Te nem vagy ROOT!!!”-ot. Ugyanezt add ki rootként, máris lefut az első rendben és nem ír ki semmit. Ez sem olyan, ami csak scriptekhez alkalmas, simán használhatod terminálban is.

Bár nyilván nem az a fő funkciója, hogy értesítéseket küldjön lefutás, vagy hiba esetén, de a legegyszerűbb hibaüzenet küldés az előbbi példa: ha hibával fut le a parancs a második egy üzenetküldési rész. Az, hogy egy sima echo és kiír valamit, vagy kdialog, zenity ablakot dob fel, az már csak részletkérdés.

Itt is igaz, hogy hibakezelésnek, vagy válaszútnak (ha nem jó, akkor tedd azt stb. ) nem ez a legprofibb módja, de egy faék egyszerűségű scriptbe nagyon megfelelő lesz.

A kettő kombinációja shell scriptben

AND – OR (&& – ||) Ez nagyban analóg az „if-else” megoldással egyes programnyelvekben, bár aki már használt if-else ágat, az nem ezt a cikket olvassa 🙂 . Azaz megadható két kimenet: ha rendben lefutott minden, akkor mit tegyen, és ha nem, akkor mit. Így egy elágazásszerűséget hozhatunk létre, különösebb programozói ismeret nélkül.

#! /usr/bin/bash
apt-get update && apt-get -y upgrade || echo „Nem sikerült az adatbázis frissítése!!!”

Azaz, ha lefut az adatbázis frissítés, akkor frissíti a csomagokat, de ha nem, akkor kiírja, hogy „Nem sikerült az adatbázis frissítése!!!”.

Eredmény átirányítása fájlba scripteknél

.. és persze sima parancssorban is így működik. Régebbi cikkekben több helyen is használtuk azt a megoldást, hogy egy parancs kimenetét nem a terminálban akartuk megnézni, hanem azt rögzíteni is kellett egy szövegfájlba. Ez scripteknél három okból lehet fontos. Az egyik értelemszerűen ha a script, vagy parancs eredménye a szövegfájl. Ilyen feladat volt a múlt részben a

#Csomaglista generálása, ha valami fontosat is leszedne...
pacman -Qqe > lista.txt

része a scriptnek. Maga az eredmény, amit akartunk egy szöveges fájl.

A másik lehetőség, amikor a kimenetet azért irányítjuk át egy fájlba, hogy azt később, vagy abban a scriptben tovább feldolgozzuk. Ilyenre jó példa a weblap változást ellenőrző scriptünk. Ott azért kellett két fájl, hogy azt összehasonlítsuk.

A harmadik cél lehet egy ellenőrzési feladat is, ha egy-egy helyen a script részeredményét kimentjük fájlba, és azt megnézzük. Érdemes minden olyan ponton készíteni egy ilyen fájlt, ahol meg szeretnénk győződni arról, hogy jól működik a script és addig azt a kimenetet kaptuk, amit vártunk. Ahogy láttuk az átirányítás módja a kacsacsőr.

pacman -Qqe > lista.txt

Ez elkészíti a listát, és kiírja a lista.txt-be. Ha van már egy lista.txt, akkor annak a tartalmát felülírja.

pacman -Qqe >> lista.txt

Ha kettő kacsacsőrt használunk, akkor nem kerül felülírásra a fájl, hanem hozzáfűzi a végéhez, így egyre nagyobb fájlt kapunk. Ez hasznos, ha folyamatosan akarjuk az eredményeket tárolni, és nem csak egyszer, vagy csak a legutolsót.

Pipe, csővezeték

Már volt róla szó, de mivel ide is tartozik, röviden ismétlek. A csővezeték, azaz a | egy nagyon hasznos eszköz. Ha van egy olyan láncfeladat, aminél az első parancs eredményét (a példában az Arch rendszerünkre telepített csomaglistát) fel kell dolgozni (pld. kiválogatni a kde-vel kezdődő csomagneveket), akkor a pipe megoldja. Gyakorlatilag valóban olyan, mintha csővezeték lenne, az egyik feladat kimenetét összeköti a következő feladat bemenetével.

pacman -Qqe | grep "kde*" > kdecsomagok.txt

Természetesen több pipe, csővezeték is mehet egymás után. Ha több és bonyolultabb parancsot fűzöl egybe, akkor már van értelme részekre szedni és közben ellenőrzés céljából a kimenetet fájlba átirányítani. Vagy használd a pipe csővezeték szerelőjét 🙂

Ok, mára ennyi lenne. Érdemes mindegyiket kipróbálni, akár CLI, akár scriptesített formában.

Kitérő! Több esetben kellemetlen, kényelmetlen lehet egy tesztelési időszakban, ha emelt joggal kell valamit futtatni, és a jelszót állandóan bekéri a script majd minden átíráskor, javításkor. Erre megoldás lehet a sudo időtartamának a megemelése. Ez nem túl jó, mert tesztelés után illő állítani, ami idő és el is szoktam felejteni. A másik megoldás már egy kicsit kockázatosabb, de ha ésszel alkalmazod, akkor nem lehet gond. A sudo nem csak a terminálba beírt jelszavakat tudja értelmezni, hanem ha egy echo jelszó | sudo -S parancsok megoldást használsz a scriptben, akkor az echo beolvassa a jelszo jelszavadat és csővezetéken átadja a sudo-nak, ami az -S kapcsoló miatt értelmezni tudja. Majd ha kész a tesztelésed, vagy befejezted a munkát, ezt a sort törlöd.

A következő részt június 20-ra időzítettem!

Related Posts