3.3 Lekcija 2
Sertifikat: |
Linux Essentials |
---|---|
Verzija: |
1.6 |
Tema: |
3 Moć komandne linije |
Cilj: |
3.3 Pretvaranje komandi u skriptu |
Lekcija: |
2 od 2 |
Uvod
U posljednjoj lekciji, koristili smo jednostavne primjere kako bismo demonstrirali pisanje Bash skripti:
#!/bin/bash # A simple script to greet a single user. if [ $# -eq 1 ] then username=$1 echo "Hello $username!" else echo "Please enter only one argument." fi echo "Number of arguments: $#."
-
Sve skripte treba da počinju sa shebang, koji definiše putanju do interpretera.
-
Sve skripte treba da sadrže komentare koji opisuju njihovu upotrebu.
-
Ova posebna skripta radi sa argumentom, koji se prosljeđuje skripti kada se ona pozove.
-
Ova skripta sadrži komandu if, koja testira uslove ugrađene varijable
$#
. Ova varijabla je postavljena na broj argumenata. -
Ako je broj proslijeđenih argumenata skripti jednak 1, tada se vrijednost prvog argumenta prosljeđuje novoj varijabli pod nazivom
username
i skripta prikazuje pozdrav korisniku. U suprotnom, prikazuje se poruka o grešci. -
Konačno, skripta ponavlja broj argumenata. Ovo je korisno za otklanjanje grešaka.
Ovo je koristan primjer za početak objašnjavanja nekih drugih karakteristika Bash skriptiranja.
Exit kodovi
Primijetit ćete da naša skripta ima dva moguća stanja: ili ispisuje "Zdravo <user>!"
ili ispisuje poruku o grešci. Ovo je sasvim normalno za mnoge naše osnovne usluge. Uzmite u obzir cat
, s kojom ste bez sumnje dobro upoznati.
Uporedimo uspješnu upotrebu cat
komande sa situacijom u kojoj ne uspijeva. Podsjetnik da je naš primjer iznad skripta pod nazivom new_script.sh
.
$ cat -n new_script.sh 1 #!/bin/bash 2 3 # A simple script to greet a single user. 4 5 if [ $# -eq 1 ] 6 then 7 username=$1 8 9 echo "Hello $username!" 10 else 11 echo "Please enter only one argument." 12 fi 13 echo "Number of arguments: $#."
Ova komanda je uspješna i primijetit ćete da je -n
opcija također ispisala brojeve redova. Oni su od velike pomoći prilikom otklanjanja grešaka u skriptama, ali imajte na umu da nisu dio skripte.
Sada ćemo provjeriti vrijednost nove ugrađene varijable $?
. Za sada samo obratite pažnju na izlaz:
$ echo $? 0
Sada razmotrimo situaciju u kojoj cat
neće uspjeti. Prvo ćemo vidjeti poruku o grešci, a zatim provjeriti vrijednost $?
.
$ cat -n dummyfile.sh cat: dummyfile.sh: No such file or directory $ echo $? 1
Objašnjenje za ovo ponašanje je sljedeće: svako izvršavanje uslužnog programa cat
će vratiti exit code. Izlazni kod (eng.Exit code) će nam reći da li je komanda uspjela ili je došlo do greške. Izlazni kod nula označava da je komanda uspješno završena. Ovo vrijedi za gotovo svaku Linux komandu s kojom radite. Bilo koji drugi izlazni kod će ukazati na neku vrstu greške. Izlazni kod last command to run bit će pohranjen u varijablu $?
.
Izlazne kodove obično ne vide ljudi, ali su vrlo korisni kada se pišu skripte. Razmislite o skripti u kojoj možda kopiramo datoteke na udaljeni mrežni disk. Postoji mnogo načina na koje zadatak kopiranja nije uspio: na primjer, naša lokalna mašina možda nije povezana na mrežu ili je udaljeni disk pun. Provjeravanjem izlaznog koda našeg uslužnog programa za kopiranje možemo upozoriti korisnika na probleme prilikom pokretanja skripte.
Vrlo je dobra praksa implementirati izlazne kodove, tako da ćemo to učiniti sada. U našem scenariju imamo dva puta, uspjeh i neuspjeh. Koristimo nulu za označavanje uspjeha, a jedan za neuspjeh.
1 #!/bin/bash 2 3 # A simple script to greet a single user. 4 5 if [ $# -eq 1 ] 6 then 7 username=$1 8 9 echo "Hello $username!" 10 exit 0 11 else 12 echo "Please enter only one argument." 13 exit 1 14 fi 15 echo "Number of arguments: $#."
$ ./new_script.sh Carol Hello Carol! $ echo $? 0
Primijetite da je komanda echo
u redu 15 u potpunosti zanemarena. Korištenje exit
će odmah završiti skriptu, tako da se na ovu liniju nikada neće naići.
Korištenje više argumenata
Za sada naša skripta može rukovati samo jednim korisničkim imenom u isto vrijeme. Bilo koji broj argumenata osim jednog će uzrokovati grešku. Hajde da istražimo kako ovu skriptu možemo učiniti raznovrsnijom..
Prvi instinkt korisnika može biti korištenje više pozicionih varijabli kao što su $2
, $3
i tako dalje. Nažalost, ne možemo predvidjeti broj argumenata koje bi korisnik mogao odabrati da koristi. Da biste riješili ovaj problem, bit će od pomoći uvesti više ugrađenih varijabli.
Izmijenit ćemo logiku naše skripte. Posjedovanje nula argumenata trebalo bi uzrokovati grešku, ali bilo koji drugi broj argumenata bi trebao biti uspješan. Ova nova skripta će se zvati friendly2.sh
.
1 #!/bin/bash 2 3 # a friendly script to greet users 4 5 if [ $# -eq 0 ] 6 then 7 echo "Please enter at least one user to greet." 8 exit 1 9 else 10 echo "Hello $@!" 11 exit 0 12 fi
$ ./friendly2.sh Carol Dave Henry Hello Carol Dave Henry!
Postoje dvije ugrađene varijable koje sadrže sve argumente proslijeđene skripti: $@
i $*
. Uglavnom, oboje se ponašaju isto. Bash će parsirati argumente i odvojiti svaki argument kada naiđe na razmak između njih. U stvari, sadržaj $@
izgleda ovako:
|
|
|
|
|
|
Ako ste upoznati sa drugim programskim jezicima, možda ćete prepoznati ovu vrstu varijable kao niz (eng.array). Nizovi u Bashu se mogu kreirati jednostavnim stavljanjem razmaka između elemenata poput varijable FILES
u skripti arraytest
ispod:
FILES="/usr/sbin/accept /usr/sbin/pwck/ usr/sbin/chroot"
Sadrži listu mnogih stavki. Za sada ovo nije bilo od velike pomoći, jer još nismo uveli nikakav način pojedinačnog rukovanja ovim stavkama.
For petlja
Osvrnimo se na arraytest
primjer prikazan prije. Ako se sjećate, u ovom primjeru specificiramo vlastiti niz pod nazivom FILES
. Ono što nam treba je način da “raspakujemo” ovu varijablu i pristupimo svakoj pojedinačnoj vrijednosti, jednoj za drugom. Da bismo to uradili, koristićemo strukturu koja se zove for petlja, koja je prisutna u svim programskim jezicima. Postoje dvije varijable na koje ćemo se pozivati: jedna je raspon, a druga je za pojedinačnu vrijednost na kojoj trenutno radimo. Ovo je skripta u cijelosti:
#!/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
Ako ponovo pogledate gornji primjer friendly2.sh
, možete vidjeti da radimo sa rasponom vrijednosti sadržanim u jednoj varijabli $@
. Radi jasnoće, nazvat ćemo posljednju varijablu username
. Naša skripta sada izgleda ovako:
1 #!/bin/bash 2 3 # a friendly script to greet users 4 5 if [ $# -eq 0 ] 6 then 7 echo "Please enter at least one user to greet." 8 exit 1 9 else 10 for username in $@ 11 do 12 echo "Hello $username!" 13 done 14 exit 0 15 fi
Zapamtite da se varijabla koju ovdje definirate može imenovati kako god želite i da će se sve linije unutar do… done
izvršavati jednom za svaki element niza. Pogledajmo izlaz iz naše skripte:
$ ./friendly2.sh Carol Dave Henry Hello Carol! Hello Dave! Hello Henry!
Sada pretpostavimo da želimo da naš rezultat izgleda malo više ljudski. Želimo da naš pozdrav bude u jednoj liniji.
1 #!/bin/bash 2 3 # a friendly script to greet users 4 5 if [ $# -eq 0 ] 6 then 7 echo "Please enter at least one user to greet." 8 exit 1 9 else 10 echo -n "Hello $1" 11 shift 12 for username in $@ 13 do 14 echo -n ", and $username" 15 done 16 echo "!" 17 exit 0 18 fi
Nekoliko napomena:
-
Korištenje
-n
saecho
će potisnuti novi red nakon ispisa. To znači da će se svi izlazi (eng.echoes) ispisati u isti red, a novi red će biti ispisan tek nakon!`
u redu 16. -
Komanda
shift
će ukloniti prvi element našeg niza, tako da ovo:
|
|
|
|
|
|
Postaje ovo:
|
|
|
|
Posmatrajmo izlaz:
$ ./friendly2.sh Carol Hello Carol! $ ./friendly2.sh Carol Dave Henry Hello Carol, and Dave, and Henry!
Korištenje regularnih izraza za provjeru greški
Moguće je da želimo provjeriti sve argumente koje korisnik unosi. Na primjer, možda želimo osigurati da sva imena proslijeđena skripti friendly2.sh
sadrže samo slova, a svi posebni znakovi ili brojevi će uzrokovati grešku. Da izvršimo ovu provjeru greške, koristit ćemo komandu grep
.
Podsjetimo da možemo koristiti regularne izraze sa grep
.
$ echo Animal | grep "^[A-Za-z]*$" Animal $ echo $? 0
$ echo 4n1ml | grep "^[A-Za-z]*$" $ echo $? 1
^
i $
označavaju početak i kraj reda redom. [A-Za-z]
označava niz slova, velikih ili malih slova. *
je kvantifikator i modificira naš raspon slova tako da uparujemo nulu s mnogo slova. Ukratko, naš grep
će uspjeti ako je unos samo slova, a u suprotnom neće uspjeti.
Sljedeća stvar koju treba primijetiti je da grep
vraća izlazne kodove na osnovu toga da li je bilo podudaranja ili ne. Pozitivno podudaranje vraća 0
, a nepodudaranje vraća 1
. Ovo možemo koristiti za testiranje naših argumenata unutar naše skripte.
1 #!/bin/bash 2 3 # a friendly script to greet users 4 5 if [ $# -eq 0 ] 6 then 7 echo "Please enter at least one user to greet." 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 "ERROR: Names must only contains letters." 16 exit 2 17 else 18 echo "Hello $username!" 19 fi 20 done 21 exit 0 22 fi
U redu 12, preusmjeravamo standardni izlaz na /dev/null
, što je jednostavan način da ga potisnemo. Ne želimo da vidimo bilo kakav izlaz iz komande grep
, želimo samo da testiramo njen izlazni kod, što se dešava u redu 13. Takođe, primetite da koristimo izlazni kod 2
da označimo nevažeći argument. Općenito je dobra praksa koristiti različite izlazne kodove za označavanje različitih grešaka; na ovaj način, pametan korisnik može koristiti ove izlazne kodove za rješavanje problema.
$ ./friendly2.sh Carol Dave Henry Hello Carol! Hello Dave! Hello Henry! $ ./friendly2.sh 42 Carol Dave Henry ERROR: Names must only contains letters. $ echo $? 2
Vođene vježbe
-
Pročitajte sadržaj 'script1.sh' ispod:
#!/bin/bash if [ $# -lt 1 ] then echo "This script requires at least 1 argument." exit 1 fi echo $1 | grep "^[A-Z]*$" > /dev/null if [ $? -ne 0 ] then echo "no cake for you!" exit 2 fi echo "here's your cake!" exit 0
Šta će prikazati ove komande?
-
./script1.sh
-
echo $?
-
./script1.sh cake
-
echo $?
-
./script1.sh CAKE
-
echo $?
-
-
Pročitatje sadržaj datoteke
script2.sh
:for filename in $1/*.txt do cp $filename $filename.bak done
Objasnite svrhu ove skripte ukoliko ste ju razumjeli.
Istraživačke vježbe
-
Kreirajte skriptu koja će uzeti bilo koji broj argumenata od korisnika i ispisati samo one argumente koji su brojevi veći od 10.
Sažetak
U ovom dijelu ste naučili:
-
Šta su izlazni kodovi, šta oni znače i kako ih implementirati
-
Kako provjeriti izlazni kod komande
-
Šta su
for
petlje i kako ih koristiti sa nizovima -
Kako koristiti
grep
, regularne izraze i izlazne kodove za provjeru unosa korisnika u skriptama.
Komande korištene u ovoj vježbi:
shift
-
Uklanja prvi element niza.
Specijalne varijable:
$?
-
Sadrži izlazni kod posljednje izvršene komande.
$@
,$*
-
Sadrže sve argumente proslijeđene skripti, kao niz.
Odgovori na vođene vježbe
-
Pročitajte sadržaj 'script1.sh' ispod:
#!/bin/bash if [ $# -lt 1 ] then echo "This script requires at least 1 argument." exit 1 fi echo $1 | grep "^[A-Z]*$" > /dev/null if [ $? -ne 0 ] then echo "no cake for you!" exit 2 fi echo "here's your cake!" exit 0
Šta će prikazati ove komande?
-
Command:
./script1.sh
Output:
This script requires at least 1 argument.
-
Command:
echo $?
Output:
1
-
Command:
./script1.sh cake
Output:
no cake for you!
-
Command:
echo $?
Output:
2
-
Command:
./script1.sh CAKE
Output:
here’s your cake!
-
Command:
echo $?
Output:
0
-
-
Pročitajte sadržaj datoteke
script2.sh
:for filename in $1/*.txt do cp $filename $filename.bak done
Objasnite svrhu ove skripte ukoliko ste ju razumjeli.
Ova skripta će napraviti rezervne kopije svih datoteka koje završavaju sa
.txt
u poddirektorijumu definisanom u prvom argumentu.
Odgovor na istraživačke vježbe
-
Kreirajte skriptu koja će uzeti bilo koji broj argumenata od korisnika i ispisati samo one argumente koji su brojevi veći od 10.
#!/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 ""