Shell funkció alapjai. Aki ezt meghallja rögvest valami nagy és összetett eszközre gondol. Pedig egy nagyon egyszerű, alap shell ismeretekkel használható megoldás.
Mi is az a shell funkció?
Mini kis programocska, amit a shell beállító állományába szoktak elhelyezni. Azaz ez sem más, mint bármilyen kis szkript, alias, amit eddig is nagyszerűen használhattunk. Bár ez a megfogalmazás nem teljesen fedi le a shell funkció fogalmát, ebben a cikkben csak ezzel a részhalmazzal fogunk foglalkozni.
Ha van olyan feladat, ami többször előfordul, akkor érdemes azt egyszer megírni, majd felhasználni. A legtöbb ilyen shell funkció valóban a mini, kis, egyszerű jelzőkkel illethető, hiszen jellemzően nem egy összetett feladatokat ellátó megoldást rakunk bele.
Akit komolyabban érdekel a téma nagyon sok jó leírást talál hozzá. Mi most valóban az alapokat ismerjük meg, és nem az elméleti hátterét. Alapokat, azaz egy mini programocska szintjét vizsgáljuk meg.
Mi a shell funkció hátránya?
Mini kis programocska, amit a shell beállító állományába szoktak elhelyezni. A beállító állomány lehet a zsh.rc. Amit akkor olvas be a zsh, ha egy terminált indítunk, azaz ha valamit a zsh.rc-be rakunk, akkor azt bash (azaz shell váltás után) alatt nem fogjuk tudni használni. Ami nem jelent gondot, mivel sima copy, paste megoldással a legtöbb esetben villámgyorsan berakhatjuk az összes esetlegesen használt shell konfigba.
Igen, van rá mód, hogy külső fájlban tároljuk a shell funkciókat, és induláskor importáljuk be a konfigurációmba, de ez már túlmutat a mostani feladatunkon.
Alap felépítése
function name() { list of commands }
A formázása ettől eltérhet, de az alapfelépítése egy névből és egy parancsokat tartalmazó részből áll. A két {} közé gyakorlatilag majdnem bármilyen szkriptet, parancsok összességét, akár komolyabb szerkezettel is elhelyezhetünk.
A funkció használata nagyon egyszerű, hiszen a fenti name funkció használata annyi, hogy a terminálba beírjuk a nevét: name és ha kell a paramétereket. Pont úgy, mint egy akármilyen más program esetén. Van olyan megoldás, amikor ezeket a funkciókat egy adott programon, szkripten belül használjuk, de most nem erről lesz szó!
Ismerős a shell funkció szerkezete!
Igen, mert más használtunk ilyent, amikor a pet két alapvető funkcióját – a mentést és a visszakeresést – beírtuk a shell konfigurációs állományába. A példa jól mutatja a hasznosságát: egy gyakran felhasználandó feladatra készült egy kényelmes parancs.
Egy példa
function extract () { if [ -f $1 ] ; then case $1 in *.tar.bz2) tar xjf $1;; *.tar.gz) tar xzf $1;; *.bz2) bunzip2 $1;; *.rar) rar x $1;; *.gz) gunzip $1;; *.tar) tar xf $1;; *.tbz2) tar xjf $1;; *.tgz) tar xzf $1;; *.zip) unzip $1;; *.Z) uncompress $1;; *) echo "'$1' cannot be extracted via extract()" ;; esac else echo "'$1' is not a valid file" fi }
Bár összetettnek tűnik, de nagyon hasznos kiegészítése lehet a shell konfigurációdnak. Az extract után megadott tömörítvényt egy case szerkezettel megvizsgáltatjuk, hogy mi annak a kiterjesztése, majd a megfelelően paraméterezett kicsomagolónak átadjuk. Ha meg egyik kiterjesztés sem egyező, akkor azt jelzi számunkra. Rövidebb, és nem felejti el az ember a pontos szintaxist. A példa analógiájára bármilyen hasonló gyors megnyitás, kezelés, tömörítés, törlés stb. megoldható.
Egy másik példa:
function psg() { if [ ! -z $1 ] ; then echo "Grepping for processes matching $1..." ps aux | grep $1 else echo "!! Need name to grep for" fi }
Sok esetben kell egy futó process-t megkeresni, ami nem túl nagy feladat, ha grep-et ismered, de jobb lenne rövidebb utat is kitalálni hozzá. Ez nagyon egyszerű, ha írsz egy nem túl összetett, de megfelelő szkriptet, vagy egy shell funkció felé nézegetsz. A fenti példa is ezt mutatja. A psg és a process név beírása után lefut a ps aux | grep parancs a process névre. A többi, az echo és a if-else szerkezet csak a felhasználhatóságot segíti. Rövidebb, és nem felejti el az ember a pontos szintaxist.
Alias, szkript, shell funkció?
Parttalan, hiábavaló és felesleges a vita, hogy melyik a jobb. Az alias nagyon jó, de a lehetőségei korlátozottabbak. Ha már egy sornál hosszabb, akkor érdemes nem ezt választani. Ha összetettebb a feladat, akkor a szkript jó választás. A hátránya az elérési útban kell lenni, vagy a teljes elérési utat meg kell adni. Ez nem jelentős akadály, hiszen a PATH-ban megadott, a szkripteket tartalmazó szabvány könyvtár és alkönyvtárai témát ismerjük…
A shell funkció előnye (ezen a szinten!!!), hogy nem kell elérési út, a shell induláskor megkapja az összes infót róla. A hátrányaként említendő: nem feltétlen egyforma a bash és a zsh, vagy akár egyéb shell. Így nem feltétlen hordozható. Ami szintén nem áthidalhatatlan, de jó ha tudjuk.
Nagy hátránya a shell funkcióknak, hogy ott, ahol nem olvassa be egy program a shell konfigurációt ott nem fog működni. Azaz például a ranger-ben sem adhatjuk meg a ranger parancssorában a funkciók nevét. Ellenben, ha egy terminált nyitunk a ranger-en belül, akkor már működik, hiszen az egy terminál…
Ami egy jó dolog: a szkript és a bemutatott funkció megoldás nagyon hasonló, így átalakítható az egyik a másikra.
Mára ennyit. Ha megtetszett, és hasznosnak találtad, akkor a github-on keress rá a shell function keresőszóra, és válogass a több száz megoldás közül. Amire figyelj: ha beírsz egy funcion-t a konfigurációs fájlba, csak az újonnan indított terminálemutorban fog működni.