
Shell Script alapok
A Shell script egy olyan programozási nyelv, ami arra lett tervezve, hogy Unix alapú rendszerek futtassák. A használata egyszerű és gyorsan megírható. Emellett ez egy scripting language, ez azt takarja, hogy nincs szükségünk külön fordítóra. A megalkotásánál az volt a cél, hogy más, Unix programokkal kompatibilis legyen. Ez később szemléltetve is lesz.
Felépítése
Minden shell script kódra jellemző, hogy ugyan úgy kezdődnek. Az első sor mindig az kódot futtató program megadása, így a rendszer tudni fogja, hogy melyik programmal kell futtatnia. Ez a következő módon néz ki:
#!/bin/bash
Ez után kezdődik maga a kód megírása. Itt a megszokott programozási nyelvektől eltérően soha nem történik modul importálása (lásd, python: import time
), mivel itt modulok helyett Unix alapú rendszerek által futtatható programokat használ a kód. A shell script kódok .sh
végződésűek. Fontos viszont, hogy a kód futtatása előtt jogot kell neki adni erre:
chmod +x elso_program.sh
Változók deklarálása
Itt a változók deklarálása egyszerűen történik. Először a már említett módon az első sorba a program megadása kerül, amivel futtatni fogja a rendszer.
Egy hello world programban először deklarálni kell a változót: VALTOZO_NEVE=valtozo_erteke
, fontos, hogy a változó neve ne használjon ékezetes karaktereket illetve helykihagyást. Következő a változó kiíratása. Ezt echo
paranccsal történik: echo $változó neve
. Az echo az utána következő argumentumok kiírásáért felel. Ha a változónak nem értéket adunk, hanem az értékét kérjük le, akkor mindig rakunk egy $
-et a változó neve elé ügyelve arra, hogy ne legyen közte szóköz.
#!/bin/bash
VAR="Hello World"
echo $VAR
Mivel ez egy scripting language így a változók deklarálása nincs túlbonyolítva, nem szükséges a típus megadása. Erre jó példa a következő kódrészlet:
string="Hello World"
number=1
float=3.142
mixed=abc123
Nem előre deklarált változók
Read
A read
parancs lehetővé teszi, hogy változóknak bemeneti értéket adjunk meg értékként. Erre egy jó példa:
echo "Mi a neved?"
read nev
echo "Helló $nev"
Itt a program kiírja, hogy Mi a neved?
, majd beolvassa a nev
változó értékét, ez után az echo
parancs segítségével pedig kiírja.
Argumentumok
Argumentumokkal már találkozhattunk. Ezek a parancs után találhatóak általában egy kötőjellel kezdődnek(például: irssi -n
Az argumentumok számozva vannak és a számozás 0-tól indul. A 0. argumentum mindig a fájlnév és utána következnek a változók.
script.sh arg1 arg2 arg3
Ezekre az argumentumokra $-el lehet hivatkozni. $, majd pedig az argumentum száma.
#!/bin/bash
echo "Fájlnév $0"
echo "1. argumentum $1"
echo "2. argumentum $2"
Ezt a programot miután elmentjük a következő képpen kell használni:
./args.sh elso masodik
Ez vissza fogja adni nekünk az fájlnév után következő első illetve második argumentumot.
If használata
At if statement egy feltételből és egy állításból áll. Erre egy egyszerű példa:
if 5 -gt 4
then
echo “5 nagyobb mint 4”
fi
Itt felmerülhet a kérdés, hogy mit jelent a -gt
, ez a “nagyobb mint”-nek felel meg, shell scriptben az operátorok mid hasonló képpen kell megadni. Ezek magyarázata:
-eq: equal to = egyenlő vele, ==
-ne: not equal to = nem egyenlő vele, !=
-lt: less than = kisebb mint, <
-le: less than or equal to = kisebb mint vagy egyenlő, <=
-gt: greater than = nagyobb mint, >
-ge: greater than or equal to = nagyobb mint vagy egyenlő, >=
Ez számokra vonatkozik, viszont fájlokkal is vannak operátorok. Ezek közül a fontosabbak:
-e a fájl létezik és
-d a fájl létezik és egy mappa
-f a fájl létezik és egy fájl
-r a fájl létezik és olvasható
-w a fájl létezik és írható
-x a fájl létezik és futtatható
-s a fájl létezik és a mérete nagyobb mint 0
Ezeket hasonló módon kell használni mint az előző példában.
if [ -e ".bash_profile" ]
then
echo " The file exists "
else
echo " File not found "
fi
While loop
A while loop addig futtatja a tartalmát újra és újra, amíg az állítása igaz. Ezt legtöbbször egy boolean változóval teszik, viszont egy változó értékének ellenőrzését is szokták while loop állításba tenni, viszont erre legtöbb esetben a for loop sokkal előnyösebb. A while loopra egy példa:
n=1
while [ $n -le 3 ]
do
echo "$n alkalommal lefutott"
n=$(( n+1 ))
done
For loop
A for loop hasonlít a while loopra, viszont ez arra lett kitalálva, hogy értéket növeljen és úgy hajtson végre utasításokat. A for loopra egy jó példa:
for num in {1..10}
do
echo "$num"
done
Ez a ciklus minden alkalommal lefut, amíg a num változó nem éri el a 10 értéket. A num változó alapértéke 1 és minden lefutás során az értéke növekszik 1-el. Ez megoldható, hogy ne 1-et lépjen ciklusonként, hanem például 10-et.
for num in {0..100..10}
do
echo "$num"
done
Ez hasonló képpen fog lefutni mint az előző példa, viszont ez esetben 1-től 100-ig 10-esével növeli a num változó értékét. A for loopot lehet többféle képpen is használni, viszont van egy mód, amit más nyelvekben is előszeretettel használnak az átláthatósága miatt.
for (( i=1; i -et 10; i++))
do
echo "$i"
done
Tömbök használata
Ez idáig véges számú változókat deklaráltunk az értékeink tárolására. Mi történik abban az esetben, ha nekünk ennél többre van szükségünk? Tételezzük fel, hogy a felhasználótól 20 értéket kérünk be. Ehhez 20 változót kellene deklarálnunk? Korántsem. A tömbök használatával dinamikusan tárolhatjuk értékeinket anélkül, hogy minden egyes értékhez egy új változót hoznánk létre. Első lépésben hozzunk létre egy új tömböt.
declare -a SZAM;
declare -A NAME;
A declare
kulcsszó létrehozza a tömböt, melyet az -a
és -A
kapcsolókkal láthatunk el. Az -a
kapcsoló egy index-alapú tömböt hoz létre. A tömb első elemének indexe minden esetben 0
és elemenként 1-el növekszik. A tömb -1
indexe mindig az utolsó elemet adja vissza.
Ezzel ellentétben az -A
kapcsoló egy asszociatív tömböt hoz létre, ahol a tömbelemek kulcsszavak alapján kerülnek indexelésre:
declare -a SZAM;
SZAM=(1 2 3 4 5 6)
#általános alak: TÖMB[index]=érték
SZAM[0]=1
SZAM[1]=2
SZAM[2]=3
SZAM[3]=4
SZAM[4]=5
SZAM[5]=6
declare -A NAME;
#általános alak: TÖMB[kulcs]=érték
NAME[manager]=Attila
NAME[dev]=Béla
NAME[devOps]=Károly
NAME[finOps]="Gipsz Jakab"
Az előbb említett asszociatív tömböt alternatív módon is létrehozhatjuk, egy sorban:
#általános alak: TÖMB=([kulcs1]=érték1 [kulcs2]=érték2...)
declare -A NAME
NAME=([manager]=Attila [dev]=Béla [devOps]=Károly [finOps]="Gipsz Jakab")
#vagy
NAME=(
[manager]=Attila
[dev]=Béla
[devOps]=Károly
[finOps]="Gipsz Jakab"
)
Fontos észrevennünk, hogy ha a tömbelemeket egy kifejezésként szeretnénk definiálni (egysoros definíció), akkor szóközökkel kell elválasztanunk őket egymástól. Ha tömbben olyan elemünk van, amely szóközöket tartalmaz, akkor idézőjelek használatával tehetjük egyértelművé, hogy az érték egy elemet alkot.
Hozzáférés a tömbelemekhez
Amennyiben a tömböt szimplán megpróbáljuk kiíratni, akkor mindig az első tömbelemet kapjuk:
SZAM=(1 2 3 4 5 6)
echo $SZAM
1
A tömbelemeket a “bash expansion” szintaktikával érhetjük el explicit módon:
SZAM=(1 2 3 4 5 6)
echo ${SZAM[0]}
1
echo ${SZAM[2]}
3
echo ${SZAM[-1]}
6
echo ${SZAM[1+1]}
3
Mint láthatjuk, a tömbelem hivatkozás lehet akár egy kifejezés is, a szabály mindösszesen annyi a szabály, hogy kifejezésnek számra kell kiértékelődnie.
Az összes tömbelemet az alábbi módokon tudjuk kiíratni:
SZAM=(1 2 3 4 5 6)
echo ${SZAM[*]}
1 2 3 4 5 6
echo ${SZAM[@]}
1 2 3 4 5 6
Látszólag a két parancs egyenértékű, de a kettő között különbség van. Az *
operátor a tömbelemet egy argumentumként írja ki, a @
viszont külön argumentumonként írja ki az elemeket. A tömböt egy for
looppal történő bejárás után a különbség nyilvánvalóvá válik:
for i in "${SZAM[*]}";do
echo "$i"
done
1 2 3 4 5 6
for i in "${SZAM[@]}";do
echo "$i"
done
1
2
3
4
5
6
A tömbelemek számát az alábbi módon írhatjuk ki:
echo ${#SZAM[@]}
6
#vagy
echo ${#SZAM[*]}
6
Asszociatív tömb kulcsainak a listázása:
echo ${!NAME[@]}
#vagy
echo ${!NAME[*]}
finOps dev manager devOps
Tömbelemek hozzáadása és törlése
Indexelt tömbökben a törlés index alapján történik. Asszociatív tömbelemeket kulcs alapját törölhetünk:
declare -A NAME
NAME=([manager]=Attila [dev]=Béla [devOps]=Károly [finOps]="Gipsz Jakab")
unset NAME[manager]
echo ${NAME[@]}
Gipsz Jakab Béla Károly
Új asszociatív tömbelem hozzáadása:
NAME=([manager]=Attila [dev]=Béla [devOps]=Károly [finOps]="Gipsz Jakab")
NAME[cleaner]=Mária
NAME+=([scrumMaster]=Ivó)
echo ${NAME[@]}
Gipsz Jakab Béla Attila Ivó Károly Mária
Mivel az értékeket kulcs határozza meg, ezért az asszociatív tömb nem rendezett. Az új érték bárhová kerülhet. Ha fontos számunkra a rendezett sorozat (és amennyiben a feladat megengedi), használjunk indexelt tömböt.
Új tömbelem beszúrása indexelt tömbökbe:
declare -a SZAM;
SZAM=(1 2 3 4 5 6)
Ha már egy létező index helyére hivatkozunk, akkor az elem felülíródik:
SZAM[3]=NaN
echo ${SZAM[@]}
1 2 3 NaN 5 6
A tömb végére pedig az alábbiképpen szórhatunk be egy új elemet:
SZAM+=Undefined
echo ${SZAM[@]}
1 2 3 NaN 5 6 Undefined
Kiírathatjuk a lista részét is, melynek általános alakja ${TOMB[@]:kezdo:elem}
. A visszatérési érték a tömbelem kezdo
indexétől számított elem
indexen át tartó altömb lesz.
echo ${SZAM[@]:3:1}
NaN
echo ${SZAM[@]:3:3}
NaN 5 6
echo ${SZAM[@]:1:5}
2 3 NaN 5 6
Összefoglaló
A shell script nagyon hasznos tud lenni, ha unix alapú rendszereken akarunk műveleteket végezni, nem szeretnénk törődni modulok importálásával, valamint összetett szintaktikák alkalmazásával. Bármely Linux felhasználónak jó szolgálatot tesz egy minimális shell script tudás, mivel ezzel felgyorsíthatjuk, kényelmesebbé tehetjük a munkánkat, hosszú távon nagyon kifizetődő. A terjedelmes, gyakran használt parancsokat automatizálhatjuk, ehhez nem kell mást tennünk, mint parancsainkat egy úgynevezett shell script fájlba írni és ezt a fájlt futtathatóvá tenni.