3.3 Lecke 2
Tanúsítvány: |
Linux Essentials |
---|---|
Verzió: |
1.6 |
Témakör: |
3 A Parancssor Erősségei |
Fejezet: |
3.3 Parancsok Szkriptté Alakítása |
Lecke: |
2 of 2 |
Bevezetés
Az előző szekcióban egy egyszerű példával mutattuk be a Bash szkriptelést:
#!/bin/bash # Egy egyszerű szkript a felhasználó üdvözléséhez. if [ $# -eq 1 ] then username=$1 echo "Hello $username!" else echo "Egy argumentumot adjon meg!" fi echo "Argumentumok száma: $#."
-
Minden szkript első sora egy shebang, amely megadja a fordító elérési útvonalát.
-
Minden szkriptben szükséges lenne a kommentezés, hogy leírjuk a használatát.
-
Ez a konkrét szkript egy argumentumot használ, amit a szkript a meghívásakor kap meg.
-
A szkript tartalmaz egy if utasítást, amely a
$#
beépített változóhoz vizsgál feltételeket. Ez a változó az argumentumok számát tartalmazza. -
Ha a szkriptnek átadott argumentumok száma 1, az első argumentum értékét átadjuk a
username
változónak és a szkript köszönti a felhasználót. Ellenkező esetben hibaüzenetet kapunk. -
Végezetül a szkript kiírja az argumentumok számát, ez a debuggolás során lehet hasznos.
Ez egy hasznos példa a Bash szkriptelés néhány funkciójának bemutatásához.
Exit Kódok
A szkriptünknek két lehetséges állapota van: kiírja, hogy "Hello <user>!"
, vagy hibaüzenetet ad. Ez sok alapvető segédprogram esetén normális. Vegyük például a cat
parancsot, amelyet már jól ismerünk.
Hasonlítsuk össze a cat
sikeres használatát egy olyan esettel, amikor nem sikerül. Ne felejtsük, hogy a fenti példánk egy new_script.sh
nevű szkript.
$ cat -n new_script.sh 1 #!/bin/bash 2 3 # Egy egyszerű szkript a felhasználó köszöntéséhez. 4 5 if [ $# -eq 1 ] 6 then 7 username=$1 8 9 echo "Hello $username!" 10 else 11 echo "Egy argumentumot adjon meg!" 12 fi 13 echo "Argumentumok száma: $#."
A parancs sikeres és láthatjuk, hogy a -n
kapcsoló kiírta a sorok számát. Ez hibakeresésnél nagyon hasznos lehet, de ne felejtsük, hogy ezek nem részei a szkriptnek!
Most nézzük meg az új beépített változónk tartalmát $?
. Egyelőre csak nézzük meg a kimenetet:
$ echo $? 0
Most nézzünk egy olyan esetet, amikor a cat
sikertelen lesz. Először egy hibaüzenetet látunk, majd nézzük meg a $? értékét
.
$ cat -n dummyfile.sh cat: dummyfile.sh: No such file or directory $ echo $? 1
Ennek a viselkedésnek a magyarázata a következő: a cat
segédprogram bármilyen futás után egy exit kódot ad vissza. Az exit kód árulja el nekünk, hogy a parancs sikeres volt-e vagy esetleg hibára futott. Egy nulla azt jelzi, hogy a parancs sikeresen lefutott. Ez majdnem minden Linux parancsra igaz, amellyel dolgozni fogunk. Bármely más exit kód valamilyen hibát jelent. Az exit kód az utolsó parancs, amit lefut és a $?
változóban tároljuk.
Az exit kódokat általában az emberi felhasználók nem látják, de nagyon hasznosak, amikor szkripteket írunk. Vegyünk egy szkriptet, amiben fájlokat másolhatunk egy távoli hálózati meghajtóra. Nagyon sok módon bukhat el a folyamat: például a mi helyi számítógépünk nem csatlakozik a hálózatra vagy a hálózati meghajtó betelt. Az exit kód ellenőrzésével figyelmeztethetjük a felhasználót a szkript futtatása során.
Az exit kódok implementálása nagyon jó gyakorlat, így most ezt is fogjuk tenni. A szkriptünkben két út van, a siker és a bukás. Jelezze a nulla a sikert és az egy a bukást.
1 #!/bin/bash 2 3 # Egy egyszerű szkript a felhasználó köszöntéséhez. 4 5 if [ $# -eq 1 ] 6 then 7 username=$1 8 9 echo "Hello $username!" 10 exit 0 11 else 12 echo "Egy argumentumot adjon meg!" 13 exit 1 14 fi 15 echo "Argumentumok száma: $#."
$ ./new_script.sh Carol Hello Carol! $ echo $? 0
Az echo
parancs a 15. sorban teljesen kimarad. Az exit
használata azonnal befejezi a szkriptet, tehát ez a sor soha nem fut le.
Több Argumentum Kezelése
Eddig a szkriptünk egyszerre csak egy felhasználónevet tudott kezelni. Egynél több argumentum megadása hibát okoz. Nézzük meg, hogyan tehetnénk a szkriptet sokoldalúbbá!
Az első ötletünk talán az lehet, hogy több pozicionális paramétert adjunk meg, mint a $2
, $3
és így tovább. Sajnos azonban nem jósolhatjuk meg, hány argumentumot használ majd a felhasználó. A probléma megoldásához hasznos lehet még több beépített változó megadása.
Módosítani fogjuk a szkript logikáját. Ha nulla argumentum van, az hibát okozhat, de bármilyen más számú argumentummal sikeresnek kell lennie. Hívjuk ezt az új szkriptet friendly2.sh
-nak.
1 #!/bin/bash 2 3 # egy barátságos szkript köszöntéshez 4 5 if [ $# -eq 0 ] 6 then 7 echo "Adjon meg legalább egy felhasználót!" 8 exit 1 9 else 10 echo "Hello $@!" 11 exit 0 12 fi
$ ./friendly2.sh Carol Dave Henry Hello Carol Dave Henry!
Két beépített változó tartalmaz minden, szkriptnek átadott argumentumot: $@
és`$*. Nagyrészt mindkettő ugyanúgy viselkedik. A Bash parszolja az argumentumokat és akkor választja el őket, amikor szóközzel találkozik köztük. Valójában a `$@
tartalma így néz ki:
|
|
|
|
|
|
Ha jártasak vagyunk más programozási nyelvekben, akkor észrevehetjük, hogy ez a változó egy tömb. A Bashben a tömbök úgy hozhatók létre, hogy az elemek közé szóközöket teszünk, mint az alábbi példában a FILES
változó esetén, az arraytest
szkriptben:
FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot"
Sok különböző elemről tartalmaz listát. Egyelőre ez nem túl hasznos, mert még nem tanultuk meg, hogyan kezelhetjük ezeket az elemeket külön-külön.
For Ciklusok
Lássuk a korábban bemutatott arraytest
példát. Ebben az esetben egy saját tömböt adtunk meg, FILES
néven. Arra van szükségünk, hogy “kicsomagoljuk” ezt a változót és egymás után hozzáférjünk az egyedi értékekhez. Ahhoz, hogy ezt megtehessük, egy for ciklus nevű struktúrára lesz szükségünk, amelyet minden programozási nyelvben használnak. Két változóra fogunk hivatkozni: az egyik a tartomány, a másik az az egyedi érték, amin épp dolgozunk. Íme a szkript, teljes egészében:
#!/bin/bash FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot" for file in $FILES do ls -lh $file done
$ ./arraytest lrwxrwxrwx 1 root root 10 Apr 24 11:02 /usr/sbin/accept -> cupsaccept -rwxr-xr-x 1 root root 54K Mar 22 14:32 /usr/sbin/pwck -rwxr-xr-x 1 root root 43K Jan 14 07:17 /usr/sbin/chroot
Ha a fenti friendly2.sh
példára hivatkozunk, láthatjuk, hogy a $@
változóban szereplő értéktartományokkal dolgozunk. Az egyszerűség kedvéért az utóbbi változó neve legyen username
. Most így néz ki a szkriptünk:
1 #!/bin/bash 2 3 # egy barátságos szkript köszöntéshez 4 5 if [ $# -eq 0 ] 6 then 7 echo "Adjon meg legalább egy felhasználót!" 8 exit 1 9 else 10 for username in $@ 11 do 12 echo "Hello $username!" 13 done 14 exit 0 15 fi
Az itt meghatározott változó tetszés szerint elnevezhető, és a do… done
-n belüli sorok legalább egyszer végrehajtódnak a tömb minden elemének esetében. Nézzük meg a szkript kimenetét:
$ ./friendly2.sh Carol Dave Henry Hello Carol! Hello Dave! Hello Henry!
Tételezzük fel, hogy azt szeretnénk, hogy a kimenetünk egy kicsit emberibbnek tűnjön. Szeretnénk, ha az üdvözletünk egy sorban lenne.
1 #!/bin/bash 2 3 # egy barátságos szkript köszöntéshez 4 5 if [ $# -eq 0 ] 6 then 7 echo "Adjon meg legalább egy felhasználót!" 8 exit 1 9 else 10 echo -n "Hello $1" 11 shift 12 for username in $@ 13 do 14 echo -n ", és $username" 15 done 16 echo "!" 17 exit 0 18 fi
Néhány jegyzet:
-
A
-n
segítségével azecho
új sort kezd a kiíratás után. Ez azt jelenti, hogy mindent egy sorba ír ki és új sor csak a!`
után lesz a 16. sorban. -
A
shift
parancs eltávolítja a tömbünk első elemét, tehát ebből:
|
|
|
|
|
|
Ez lesz:
|
|
|
|
Nézzük meg a kimenetet:
$ ./friendly2.sh Carol Hello Carol! $ ./friendly2.sh Carol Dave Henry Hello Carol, és Dave, és Henry!
Reguláris Kifejezések Használata Hibaellenőrzéshez
Lehetséges, hogy a felhasználó által megadott összes argumentumot ellenőrizni akarjuk. Például azt szeretnénk biztosítani, hogy minden friendly2.sh
számára átadott név csak betűket tartalmazzon és bármilyen speciális karakter vagy szám hibát dobjon. Ahhoz, hogy ez a hibaellenőrzés megtörténjen, grep
szükséges.
Emlékezzünk vissza, hogyan használhatunk reguláris kifejezéseket a grep
esetén.
$ echo Animal | grep "^[A-Za-z]*$" Animal $ echo $? 0
$ echo 4n1ml | grep "^[A-Za-z]*$" $ echo $? 1
A ^
és a $
sor elejét és a sor végét jelölik. A [A-Za-z]
betűtartományt jelöl, kis/nagybetűk egyaránt. A *
egy quantifier, úgy módosítja a tartományt, hogy nulla és sok betű megfeleljen. Összefoglalva, a grep
akkor lesz sikeres, ha az input csak betűkből áll, másképp elbukik.
A következő, amit tudnunk kell, hogy a grep
exit kódokkal tér vissza, attól függően, hogy volt-e egyezés vagy sem. Az egyezés 0
, a nincs egyezés pedig 1
. Ennek segítségével tesztelhetjük az argumentumainkat a szkripten belül.
1 #!/bin/bash 2 3 # egy barátságos szkript köszöntéshez 4 5 if [ $# -eq 0 ] 6 then 7 echo "Adjon meg legalább egy felhasználót!" 8 exit 1 9 else 10 for username in $@ 11 do 12 echo $username | grep "^[A-Za-z]*$" > /dev/null 13 if [ $? -eq 1 ] 14 then 15 echo "HIBA: A nevek csak betűket tartalmazhatnak." 16 exit 2 17 else 18 echo "Hello $username!" 19 fi 20 done 21 exit 0 22 fi
A 12-es sorban a standard kimenetet átirányítjuk a /dev/null
-ba, ami egy egyszerű mód az eltüntetésére. Nem akarunk semmiféle kimenetet látni a grep
parancsból, csak az exit kódját akarjuk tesztelni, ez pedig a 13-as sorban történik meg. A 2
exit kódot használjuk az érvénytelen argumentum jelzésére. Általában bevett gyakorlat, hogy a különböző hibák jelzésére különböző exit kódokat használnak; így egy hozzáértő felhasználó ezeket a kódokat felhasználhatja a hibaelhárítás során.
$ ./friendly2.sh Carol Dave Henry Hello Carol! Hello Dave! Hello Henry! $ ./friendly2.sh 42 Carol Dave Henry HIBA: A nevek csak betűket tartalmazhatnak. $ echo $? 2
Gyakorló Feladatok
-
Nézzük meg a
script1.sh
tartalmát:#!/bin/bash if [ $# -lt 1 ] then echo "A szkriptnek legalább 1 argumentum kell." exit 1 fi echo $1 | grep "^[A-Z]*$" > /dev/null if [ $? -ne 0 ] then echo "nincs süti!" exit 2 fi echo "itt a sütid!" exit 0
Mi az alábbi parancsok kimenete?
-
./script1.sh
-
echo $?
-
./script1.sh cake
-
echo $?
-
./script1.sh CAKE
-
echo $?
-
-
Nézzük meg a
script2.sh
tartalmát:for filename in $1/*.txt do cp $filename $filename.bak done
Határozzuk meg ennek a szkriptnek a célját!
Gondolkodtató Feladatok
-
Hozzunk létre egy szkriptet, amely tetszőleges számú argumentumot kezel és csak azokat az argumentumokat írja ki, amelyek 10-nél nagyobb számok!
Összefoglalás
Ebben a leckében megtanultuk:
-
Mik azok az exit kódok, mit jelentenek és hogyan implementálhatjuk őket
-
Hogyan nézhetjük meg egy parancs exit kódját
-
Mi a
for
ciklus és hogyan használhatjuk tömbök esetén -
A
grep
, reguláris kifejezések és exit kódok használata a felhasználói bemenet ellenőrzésére szkriptek esetén.
A gyakorlatok során használt parancsok:
shift
-
Egy tömb első elemének eltávolítása.
Speciális Változók:
$?
-
Az utolsó lefuttatott parancs exit kódja.
$@
,$*
-
A szkriptnek átadott összes argumentum, tömbként.
Válaszok a Gyakorló Feladatokra
-
Nézzük meg a
script1.sh
tartalmát:#!/bin/bash if [ $# -lt 1 ] then echo "A szkriptnek legalább 1 argumentum kell." exit 1 fi echo $1 | grep "^[A-Z]*$" > /dev/null if [ $? -ne 0 ] then echo "nincs süti!" exit 2 fi echo "itt a sütid!" exit 0
Mi az alábbi parancsok kimenete?
-
Parancs:
./script1.sh
Kimenet:
Ennek a szkriptnek legalább egy argumentum kell.
-
Parancs:
echo $?
Kimenet:
1
-
Parancs:
./script1.sh cake
Kimenet:
nincs süti!
-
Parancs:
echo $?
Kimenet:
2
-
Parancs:
./script1.sh CAKE
Kimenet:
itt a sütid!
-
Parancs:
echo $?
Kimenet:
0
-
-
Nézzük meg a
script2.sh
tartalmát:for filename in $1/*.txt do cp $filename $filename.bak done
Határozzuk meg ennek a szkriptnek a célját!
Ez a szkript biztonsági másolatot készít az összes
.txt
kiterjesztésű fájlról egy olyan almappában, amit az első argumentumban határozunk meg.
Válaszok a Gondolkodtató Feladatokra
-
Hozzunk létre egy szkriptet, amely tetszőleges számú argumentumot kezel és csak azokat az argumentumokat írja ki, amelyek 10-nél nagyobb számok!
#!/bin/bash for i in $@ do echo $i | grep "^[0-9]*$" > /dev/null if [ $? -eq 0 ] then if [ $i -gt 10 ] then echo -n "$i " fi fi done echo ""