nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 15.10.2022.

trejler_olovka Poslednja izmena: 17.05.2023.

trejler_dokument Jezici: Shell

trejler_teg_narandzasti Težina: 8/10

linux
gnu/linux
unix
open source
slobodni softver
Shell
regularni izrazi
regex
komandna linija
datoteke
optimizacija
teorija
saveti
zanimljivosti

Tema: GNU/Linux

1. deo - Uvod2. deo - Osnovne komande3. deo – Napredne komande

Povezani članci

ASCII, Unicode i UTF - Predstavljanje znakova na računarimaUNIX Time - Predstavljanje datuma i vremena na računarimaIzbor prvog programskog jezikaRegularni izrazi - napredna pretraga tekstaPokretanje lokalnog web serveraUvod u PythonPostfiksna notacija - kako računari računaju?Operacije sa tekstualnim datotekama u programskim jezicima C i PythonŠablonske niske u programskim jezicimaCallback funkcije i lambda izraziOperacije sa bitovima u programskom jeziku CKako napraviti syntax highlighter
Svi članci
Complexity kills. It sucks the life out of developers, it makes products difficult to plan, build and test, it introduces security challenges, and it causes end-user and administrator frustration.
Ray Ozzie

GNU/Linux - 4. deo – Shell skripte i automatizacija procesa

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Teorija

Uvod

Posle upoznavanja sa osnovnim i napredni(ji)m konzolnim komandama (što je procedura koja svakako podrazumeva i samostalno isprobavanje primera, pravilno 'taloženje informacija' i povremeno utvrđivanje gradiva), na red dolazi upoznavanje sa različitim metodama za automatizaciju procesa ....

Glavna tema članka biće kreiranje i pokretanje shell skripti u okruženju Bash, ali, prvo ćemo se upoznati sa privilegijama za pristup datotekama i direktorijumima, budući da bez dodele odgovarajućih privilegija - doslovno nije moguće pokretati skripte. :)

Na kraju (nakon detaljnog upoznavanja sa prethodno navedenim temama), upoznaćemo se ukratko i sa programima watch i cron koji takođe predstavljaju mehanizme za automatizaciju procesa u UNIX-olikim operativnim sistemima (i mogu 'sarađivati' sa shell skriptama).

Kratak osvrt na kompatibilnost skripti

Striktno govoreći, shell skripte u UNIX-olikim operativnim sistemima nisu univerzalne i svako shell okruženje u kome se skripte izvršavaju (Bash, Zsh, Fish, Dash i sl) - donosi sa sobom pojedinosti o kojima se mora voditi računa.

Na primer, nije zagarantovano da skripta, napisana za Bash shell, može da se izvršava u drugim okruženjima i sl.

Međutim, u praksi - pogotovo na početku - gotovo je sigurno da ćete kao shell program koristiti upravo Bash, ** a ako ne koristite Bash, gotovo je sigurno da koristite Zsh ili Fish.

Za Fish smo još u uvodnom članku naveli da koristi sopstvenu shell sintaksu koja nije kompatibilna sa sintaksom okruženja Bash, * a što se tiče Zsh-a, skripte pisane za Bash su kompatibilne sa okruženjem Zsh (gotovo uvek), pri čemu najčešće važi i obrnuto (autor ovog teksta koristi upravo Zsh kao (glavni) shell program, ali, sve skripte koje ćete videti u članku, uspešno su isprobane u oba okruženja).

Najjednostavnije: može se reći da sintaksa okruženja Bash predstavlja de facto standard za pisanje shell skripti pod Linux-om (duži niz godina unazad), i zato će i primeri koje ćemo prikazivati biti usklađeni sa navedenim okolnostima.

* Hteli smo da napišemo ".... da ćete koristiti baš Bash", ali - "odustali smo na vreme". :)

** Fish je svakako interesantan i praktičan shell program, ali (iako postoji mogućnost da se u nekom trenutku posvetimo pisanju "Fish skripti"), ovoga puta ćemo se zadržati na daleko uobičajenijim Bash skriptama (koje se skoro uvek mogu izvršavati i u okruženju Zsh).

Kada su u pitanju privilegije za pristup direktorijumima i datotekama (tema sledećeg poglavlja, direktno u nastavku), deluje da ima "podosta teksta za čitanje" (što ste možda već ustanovili ako ste "na brzaka premotali članak", da vidite "šta vas čeka"), ali - gradivo je vrlo jednostavno za razumevanje, i pri tom (kao što smo već naveli), krajnje je neophodno da skriptama koje kreiramo budu dodeljene odgovarajuće privilegije za izvršavanje u okviru operativnog sistema (što - iako možda deluje "čudno" na prvi pogled - nije nešto što se dešava "samo od sebe").

Privilegije korisnika za pristup datotekama i direktorijumima

Kao što smo naveli još u uvodnom članku, UNIX-oliki operativni sistemi odlikuju se preciznim i nedvosmislenim sistemom privilegija za pristup datotekama i direktorijumima.

Za svaku datoteku ili direktorijum, jasno su definisane privilegije:

  • vlasnika datoteke (vlasnik = korisnik koji je kreirao datoteku)
  • grupe korisnika kojoj vlasnik pripada
  • (svih) ostalih korisnika (koji ne pripadaju jednoj od prethodne dve kategorije)

Da bismo se upoznali sa sistemom privilegija u praksi, dovoljno je pokrenuti komandu ls -l (pri čemu ćemo dobiti, kao što znamo od ranije, detaljan tabelarni listing datoteka i direktorijuma).

		
$ ls -l
drwxr-xr-x  2 korisnik_1 admin 4096 Aug 17  2022 data
-rw-r--r--  1 korisnik_1 admin  743 Aug 25  2022 .config
		
	
Slika 1. - Primer izvršavanja komande ls.

Može se primetiti da je vlasnik direktorijuma data i datoteke .config, korisnik korisnik_1 (koji pripada grupi admin), * a mogu se primetiti i podaci koji se tiču privilegija vlasnika i ostalih kategorija korisnika (podaci se nalaze sa leve strane, u prvoj koloni koja sadrži 10 znakova).

* Usput: iako naziv deluje veoma 'zvanično', grupa admin nije jedna od sistemski generisanih grupa (sa visokim nivoom privilegija).

Prvi znak prikazuje da li je u pitanju direktorijum (d), ili je u pitanju obična datoteka (-), a sledeće tri troslovne niske definišu (kao što smo prethodno naveli): privilegije vlasnika datoteke, privilegije grupe kojoj vlasnik pripada, i (na kraju), privilegije svih ostalih korisnika.

U konkretnom primeru koji smo prikazali, ako se usmerimo na direktorijum data, mogu se zapaziti sledeće informacije:

  • d - u pitanju je direktorijum (uz obične datoteke, na prvom mestu stoji odrednica -)
  • rwx - vlasnik ima sve privilegije za pristup direktorijumu *
  • r-x - korisnici iz grupe kojoj vlasnik pripada, imaju privilegije pristupa (r) i izvršavanja (x)
  • r-x - svi ostali korisnici takođe imaju privilegije pristupa i izvršavanja

* U konkretnom primeru vlasnik datoteke tj. direktorijuma ima sve privilegije (i najčešće jeste tako), ali ne mora uvek biti tako.

(U nastavku ćemo se upoznati sa razlozima.)

U zavisnosti od toga da li je u pitanju datoteka ili direktorijum, svaka od tri troslovne niske prikazuje (redom) sledeće privilegije:

  • r - korisnik ili grupa korisnika ima privilegiju čitanja (datoteka se može čitati (tj. otvarati), odnosno, može se pristupiti direktorijumu)
  • w - korisnik ili grupa korisnika ima pravo upisa (u datoteku ili direktorijum)
  • x - korisnik ili grupa korisnika ima pravo da pokrene izvršnu datoteku
  • - - pojava znaka - na bilo kom od tri mesta, označava da je privilegija uskraćena

Pravi smisao privilegija za pristup, najlakše je razumeti preko dodatnih primera.

Iskustvo pokazuje da većina novih korisnika smatra da postoje određene privilegije koje se ("ipak") podrazumevaju, a da li je zaista tako .... videćemo (?!) ....

Najočigledniji primer je sledeći: "nekako deluje" da određeni korisnik "ipak" može pristupiti direktorijumu čiji je 'vlasnik' - bez obzira na to "šta piše u tim čudnim rwx niskama" - međutim - privilegije su sasvim nedvosmislene.

Zamislićemo da su u početnoj situaciji definisane sledeće privilegije za direktorijum /home/korisnik_1 ....

		
drwxr-xr-x 21 korisnik_1 korisnik_1 4.0K Mar 15 10:31 korisnik_1
		
	
Slika 2. - Primer privilegija za pristup (privilegije se odnose na home direktorijumu korisnika korisnik_1).

.... nakon čega nastaje (nova) situacija, u kojoj su privilegije promenjene (primetite da drugi znak, odnosno, prvi znak u prvoj troslovnoj niski, nije više 'r'):

		
d-wxr-xr-x 18 korisnik_1 korisnik_1 4.0K Mar 15 10:31 korisnik_1
		
	
Slika 3. - Primer izmenjenih privilegija sa slike #2.

U novonastaloj situaciji, korisnik korisnik_1 doslovno neće više biti u stanju da pristupa sopstvenom home direktorijumu!

.... ali, da sve bude 'zanimljivije', ostali korisnici - mogu pristupati direktorijumu.

Naravno, takve stvari se u praksi dešavaju retko, ali, jesu moguće (i te kako).

U sledećem primeru, korisnik korisnik_2 je vlasnik datoteke skripta_1.sh i definisao je privilegije na sledeći način:

		
-rwxrwxr-x 21 korisnik_2 admin 1.0K Jun 04 10:31 skripta_1.sh
		
	
Slika 4. - Primer privilegija za pristup datoteci skripta_1.sh, čiji je vlasnik korisnik korisnik_2.

U navedenoj situaciji, različiti korisnici imaju sledeće privilegije:

  • korisnik korisnik_2 ima sve privilegije
  • korisnici iz grupe admin (kojoj pripada korisnik korisnik_2), takođe imaju sve privilegije
  • ostali korisnici, imaju privilegiju čitanja (mogu otvarati skriptu u editorima i sl), imaju privilegiju pokretanja skripte, ali, nemaju privilegije za modifikaciju sadržaja skripte

U prethodno navedenim okolnostima, svi korisnici (tj. administratori) iz grupe "admin", mogu menjati sadržaj skripte skripta_1.sh, čiji je vlasnik korisnik korisnik_2 (pri čemu ostali korisnici mogu otvarati skriptu), međutim, u drugim okolnostima, mogu se podesiti drugačije privilegije:

		
-rwxr-x--x 21 korisnik_2 admin 1.0K Jun 04 10:31 skripta_1.sh
		
	
Slika 5. - Primer izmenjenih (i ponešto 'restriktivnijih') privilegija za pristup datoteci skripta_1.sh, čiji je vlasnik korisnik korisnik_2.

U novim okolnostima:

  • korisnici iz grupe "admin" mogu samo čitati i pokretati skriptu (na primer, 'pao je dogovor' da svaki administrator ubuduće uređuje samo svoje skripte)
  • ostali korisnici (poslednja troslovna niska), mogu samo pokretati skriptu

Predstavljanje privilegija preko brojčanih kodova

U opštem smislu, "rwx niske" su (naravno/očigledno) - niske, ali, takve niske se lako mogu zamisliti i kao trocifreni binarni brojevi (sa uključenim ili isključenim bitovima na određenim pozicijama), to jest, praktičnije, "rwx niske" se mogu zamisliti kao oktalne cifre (koje odgovaraju kombinacijama uključenih "bitova").

Pogledajmo nekoliko primera:

  • rwx => 111(2) => 7(8)
  • rw- => 110(2) => 6(8)
  • r-x => 101(2) => 5(8)
  • r-- => 100(2) => 4(8)

Poznavanje 'oktalnih kodova' za "rwx" statuse, biće od pomoći pri korišćenju komande chmod.

.... i stoga će (na ovom mestu), mnogi čitaoci biti zahvalni sami sebi što su se na vreme upoznali sa binarnim brojevima (a ako nije tako - verujemo da ni sada nije kasno za "nadoknađivanje propuštenog"). :)

chmod - promena privilegija datoteke/direktorijuma

Preko komande chmod ("Change Mode"), moguće je definisati (nove) privilegije za pristup određenoj datoteci, ili određenom direktorijumu.

Komanda chmod može se pozivati na razne načine, a za početak ćemo razmotriti najjednostavniji primer:

		
$ chmod u+x skripta_1.sh
		
	
Slika 6. - Primer izmene privilegija za datoteku skripta_1.sh, preko komande chmod (vlasniku datoteke se dodeljuje privilegija izvršavanja).

.... pri čemu argument u+x znači da vlasnik dobija privilegiju izvršavanja datoteke.

u je skraćeno od user (u navedenom kontekstu - vlasnik datoteke ili direktorijuma).

x je skraćeno od execute.

+ označava dodelu privilegija.

Ako je potrebno (praktično) poništiti dodelu privilegija iz prethodnog koraka, možemo pozvati sledeću komandu:

		
$ chmod u-x skripta_1.sh
		
	
Slika 7. - Primer izmene privilegija za datoteku skripta_1.sh, preko komande chmod (vlasniku datoteke se oduzima privilegija izvršavanja).

U drugom slučaju, u pitaju je oduzimanje tj. uskraćivanje privilegija, preko argumenta -.

Ako je potrebno dopuniti privilegije, tako da korisnik (tj. vlasnik) dobije privilegije izvršavanja, a grupa kojoj korisnik pripada dobije privilegije upisa, komanda se može izvršiti na sledeći način:

		
$ chmod u+x,g+w skripta_1.sh
		
	
Slika 8. - Primer izmene privilegija za datoteku skripta_1.sh, preko komande chmod (vlasniku datoteke se dodeljuje privilegija izvršavanja, a grupi korisnika kojoj pripada vlasnik datoteke, dodeljuje se privilegija upisa).

Vlasnik (u), dobija privilegije izvršavanja (+x), a grupa (g), kojoj korisnik pripada, dobija privilegije upisa (+w).

Ako je potrebno izvršiti (umesto prethodne komande), komandu preko koje ....

  • vlasnik dobija privilegiju izvršavanja
  • grupa kojoj vlasnik pripada dobija privilegiju upisa
  • svi ostali korisnici gube privilegiju čitanja

.... komanda se može dopuniti na sledeći način:

		
$ chmod u+x,g+w,a-r skripta_1.sh
		
	
Slika 9. - Primer izmene privilegija za datoteku skripta_1.sh, preko komande chmod: vlasniku datoteke se dodeljuje privilegija izvršavanja; grupi korisnika kojoj pripada vlasnik datoteke dodeljuje se privilegija upisa; svim ostalim korisnicima se ukida privilegija čitanja.

Komande koje smo koristili u nekoliko poslednjih primera, sasvim su adekvatne (same po sebi), ali, deluju previše "opširno", i stoga - za primere sa više izmena privilegija - u praksi se gotovo uvek koriste oktalni kodovi (sa kojima smo se prethodno upoznali).

Korišćenje oktalnih kodova podrazumeva malo drugačiji način razmišljanja: nećemo (u praktičnom smislu) više razmišljati o tome "kom korisniku ili grupi korisnika treba dodeliti ili ukinuti koju privilegiju", već, samo o tome kako na kraju treba da budu definisani (novi) nivoi privilegija za sve tri grupe korisnika.

Za primer ćemo uzeti krajnje tipičnu situaciju, koja je (ujedno) usko povezana sa tematikom članka.

Prvi korak u kreiranju nove skripte podrazumeva (skoro uvek) - kreiranje nove prazne datoteke preko komande touch:

		
$ mkdir ~/skripte
$ cd ~/skripte
$ touch skripta_1.sh
		
	
Slika 10. - Primer kreiranja nove prazne datoteke (tj. "buduće skripte"), uz prethodno kreiranje direktorijuma u koji će skripta biti smeštena.

Datoteka koja je kreirana na prikazani način ima sledeće privilegije:

		
-rw-r--r-- 1 korisnik_1 admin 0 Apr 02 09:18 skripta_1.sh
		
	
Slika 11. - Podrazumevane privilegije za datoteku koja se kreira preko komande touch.

.... i može se primetiti da privilegija izvršavanja (x), nije navedena ni na jednom mestu.

Postojeće (uključene) privilegije, mogu se svesti na oktalni kod 644, po sledećem postupku:

  • rw- r-- r-- se može shvatiti kao 110 100 100
  • 110 100 100 - posle prevođenja u oktalni oblik - postaje 644.

Pošto je potrebno svim korisnicima dodeliti privilegiju izvršavanja - preko oktalnog koda (to jest, da budemo precizni, potrebno je da se u sve tri grupe aktivira atribut x), može se razmišljati na sledeći način:

  • rw- r-- r-- je početna niska, koja, posle uključivanja privilegija upisa (na sva tri mesta), postaje rwx r-x r-x
  • rwx r-x r-x se može shvatiti kao 111 101 101
  • 111 101 101 - posle prevođenja u oktalni oblik - postaje 755

Pošto smo sagledali "idejno poreklo" argumenta 755, privilegije za pokretanje skripte najlakše je dodeliti (odnosno izmeniti) preko sledeće naredbe:

		
$ chmod 755 skripta_1.sh
		
	
Slika 12. - Skraćeni (i praktičniji) način zadavanja privilegija za pristup datoteci (preko komande chmod).

Statusi 644 i 755 su (daleko) najtipičniji statusi i najčešće ćete se susretati upravo sa dva navedena statusa.

Takođe, statusi 644 i 755 se mogu shvatiti na sledeći način:

  • u oba slučaja, vlasnik ima privilegije čitanja i upisa, a grupa kojoj vlasnik pripada i svi ostali korisnici, samo privilegiju čitanja (niko osim vlasnika nema privilegiju upisa)
  • status 644 označava da svi navedeni korisnici imaju prvobitno navedene privilegije, ali - nemaju privilegiju izvršavanja datoteke
  • status 755 označava da svi navedeni korisnici imaju prvobitno navedene privilegije - i pri tom imaju privilegiju izvršavanja datoteke

Pored statusa 644 i 755, prilično često se sreće i status 775 (ostali korisnici iz grupe kojoj vlasnik pripada - takođe imaju privilegiju upisa).

chown - promena vlasnika datoteke/direktorijuma

Promena vlasnika datoteke ili direktorijuma, obavlja se preko komande chown ("Change Owner").

Na primer, u sledećoj situaciji:

		
-rwxr-xr-x 1 korisnik_2 admin 0 Mar 17 09:18 skripta_1.sh
		
	
Slika 13. - Primer privilegija za pristup datoteci skripta_1.sh (vlasnik datoteke je korisnik korisnik_2).

.... posle izvršavanja komande chown:

		
$ chown korisnik_1 skripta_1.sh
		
	
Slika 14. - Poziv komande chown, preko koje se menja vlasnik datoteke.

.... datoteka (čiji je dotadašnji vlasnik bio korisnik korisnik_2), dobija novog vlasnika (novi vlasnik je korisnik korisnik_1):

		
-rwxr-xr-x 1 korisnik_1 admin 0 Mar 17 09:18 skripta_1.sh
		
	
Slika 15. - Primer izmenjenih privilegija za pristup datoteci skripta_1.sh - novi vlasnik je korisnik korisnik_1.

Ukoliko je prethodni vlasnik datoteke root korisnik:

		
-rwxr-xr-x 1 root root 0 Mar 17 09:18 skripta_x.sh
		
	
Slika 16. - Primer privilegija za pristup datoteci skripta_x.sh (vlasnik datoteke je root korisnik).

.... potrebno je komandu chown pozvati preko komande sudo:

		
$ sudo chown korisnik skripta_x.sh
		
	
Slika 17. - Poziv komande chown, preko koje se menja vlasnik datoteke (komanda chown se ovoga puta poziva preko komande sudo, budući da je vlasnik datoteke root korisnik).

.... posle čega (slično prethodnom primeru), nastaje sledeći rezultat:

		
-rwxr-xr-x 1 korisnik_1 admin 0 Mar 17 09:18 skripta_x.sh
		
	
Slika 18. - Primer izmenjenih privilegija za pristup datoteci skripta_x.sh - novi vlasnik je korisnik korisnik_1.

Sada je vreme da se usmerimo na kreiranje skripti.

Prikazaćemo prvo tipičan postupak kreiranja i pokretanja skripte, a u nastavku ćemo se baviti tipovima podataka u shell skriptama i kontrolnim strukturama (naravno, uz odgovarajuće propratne primere).

Kreiranje i pokretanje skripti

Za početak, potrebno je pripremiti zaseban direktorijum sa prigodnim nazivom skripte (ubuduće ćemo u navedeni direktorijum smeštati sve skripte):

		
$ mkdir ~/skripte
$ cd ~/skripte
		
	
Slika 19. - Priprema direktorijuma u koji će biti smeštene skripte.

U svakodnevnom radu (onda kada ne budete više pisali skripte za vežbu), preporučujemo da skripte opšteg tipa (to jest skripte za automatizaciju svakodnevnih procesa), držite u dot direktorijumu ~/.skripte.

U opštem smislu, savet je: držite sve skripte u jednom direktorijumu - zarad preglednosti (osim ako nemate jasnu ideju za još bolju organizaciju, preko dodatnih direktorijuma).

Na UNIX-olikim sistemima, tipična procedura za kreiranje i pokretanje (nove) skripte, podrazumeva:

  • kreiranje prazne datoteke
  • dodeljivanje privilegija za pokretanje novoj (praznoj) datoteci
  • unos sadržaja (tj. komandi), u datoteku
  • čuvanje datoteke i pokretanje skripte

Prazna datoteka može se kreirati preko komande touch (koja je poznata od ranije) ....

		
$ touch skripta_01.sh
		
	
Slika 20. - Kreiranje nove prazne datoteke.

.... i potom se datoteka može otvoriti u bilo kom tekstualnom editoru (shell skripte su, u tehničkom smislu, tekstualne datoteke).

Kao i obično, primere koje budemo prikazivali, čuvajte u zasebnim datotekama sa prigodnim nazivima (tj. nemojte sve primere isprobavati preko jedne datoteke). :)

Privilegije za pokretanje datoteke (tj. 'buduće skripte'), podesićemo preko komande chmod:

		
$ chmod 755 skripta_01.sh
		
	
Slika 21. - Izmena privilegija za datoteku skripta_01.sh (u praktičnom smislu - svim korisnicima se dodeljuje privilegija izvršavanja skripte).

.... ili, jednostavnije:

		
$ chmod +x skripta_01.sh
		
	
Slika 22. - Skraćeni način za dodelu privilegija izvršavanja (za novu skriptu).

Iskoristili smo priliku da se usput upoznamo sa još jednom opcijom pri korišćenju komande chmod: ukoliko se ne navede kategorija korisnika, određena privilegija se dodeljuje ili ukida svim kategorijama korisnika.

U skriptu ćemo uneti sledeći sadržaj:

		
#!/bin/bash

# promenljive:
direktorijum=/home/korisnik_1/
datoteka=/home/korisnik_1/.skripte/listing_home

# izvršne komande:
ls -lha $direktorijum > $datoteka
		
	
Slika 23. - Sadržaj skripte skripta_01.sh.

.... i (na kraju), skripta se može pokrenuti na sledeći način:

		
[korisnik_1@codeblog ~/.skripte] $ ./skripta_01.sh
		
	
Slika 24. - Primer pokretanja skripte skripta_01.sh.

U praktičnom smislu, primećujemo da skripta smešta (tabelarni) listing direktorijuma /home/korisnik_1 - u datoteku /home/korisnik_1/.skripte/listing_home.

Što se tiče 'tehnikalija', osvrnimo se na sledećih nekoliko detalja:

  • komentari u shell skriptama počinju znakom # (što znamo od ranije), ali ....
  • direktiva #!/bin/bash nije komentar, već, nalog operativnom sistemu da skriptu izvrši preko konkretnog shell programa (u primeru koji smo prikazali, u pitanju je Bash)

Primećujemo i to da smo u skripti koristili promenljive, što možemo smatrati dobrim uvodom u tematiku upotrebe promenljivih u shell skriptama (a upoznaćemo se uskoro i sa kontrolnim strukturama) ....

Promenljive u shell skriptama

Promenljive u shell skriptama, definišu se (kao što smo već videli), na vrlo neposredan način (slično kao u Python-u) ....

		
#!/bin/bash

a=10
b=15
		

	
Slika 25. - Primer deklaracije i inicijalizacije promenljivih u shell skriptama.

.... i pozivaju se uz prefiks $ (slično kao u PHP-u) * ....

		
#!/bin/bash

echo "a = $a, b = $b"
# ispis: a = 10, b = 15
		

	
Slika 26. - Primer korišćenja promenljivih u shell skriptama.

Deklaracija i inicijalizacija promenljivih u shell skriptama jeste veoma nalik deklaraciji i inicijalizaciji promenljivih u 'uobičajenijim' programskim jezicima * (najveća je sličnost sa Python-om), ali, aritmetičke i logičke operacije obavljaju se na nešto drugačiji način.

U svakom slučaju, na ovom mestu ćemo pretpostaviti da čitaoci (koji su zainteresovani za upoznavanje sa shell skriptama), imaju prethodnog iskustva u programiranju i solidno poznaju bar jedan programski jezik, ** i stoga nećemo "taksativno nabrajati" operacije, već ćemo izneti zapažanja koja se tiču razlika u odnosu na pristup koji je poznat od ranije.

* Naravno, prikazana sintaksa se pojavila u shell skriptama (godinama) pre nastanka PHP-a i Python-a.

** U praktičnom smislu, može se reći da upoznavanje sa shell skriptama bez prethodnog poznavanja C-a (ili bar Python-a), predstavlja prilično težak zadatak (mada, sa druge strane, nije ni nemoguće). :)

"Optimalna kombinacija" za početno upoznavanje sa shell skriptama, podrazumeva da se korisnik prethodno temeljno upoznao sa C-om i Python-om (i to baš navedenim redosledom).

Aritmetičke operacije sa promenljivama

Kada je u pitanju obavljanje aritmetičkih i logičkih operacija, potrebno je prvo razumeti da se sintaksa shell skripti idejno razlikuje od sintakse (velike većine) programskih jezika.

Razlike nisu "drastične", ali postoje.

Skripte se (doslovno) pokreću u okruženju koje je namenjeno interpretiranju konzolnih naredbi - pre nego interpretiranju naredbi kao što su c = a + b; ili if (a > 5) printf("Pozdrav!");, i stoga ne čudi što u svemu važe "druga pravila".

Pojava ("jednostrukih") zagrada, praktično pokreće novo shell okruženje u kome se mogu izvršavati programi, a rezultat izvršavanja se (nadalje) može dodeliti promenljivoj ....

		
datum_i_vreme=$(date)
		
	
Slika 27. - Primer promene konteksta interpretacije preko zagrada.

.... korisna opcija kojoj ćemo više pažnje posvetiti u narednim poglavljima ....

.... međutim, na ovom mestu, od većeg značaja je mogućnost uvođenja shell interpretatora u režim tumačenja algebarskih izraza - navođenjem "dupliranih" zagrada na početku i na kraju izraza:

		
c=$((a + b))
		
	
Slika 28. - Primer procene vrednosti algebarskog, uvođenjem skripte u 'aritmetički kontekst' (preko "dupliranih zagrada").

Kada se shell interpretator uvede u kontekst tumačenja algebarskih izraza (tzv. "aritmetički kontekst"), nije više potrebno navoditi prefiks $ pri obraćanju promenljivama, a dozvoljeno je koristiti i razmake u izrazima (zarad preglednosti).

Shodno navedenom, prethodni izraz može se zapisati i na sledeći način:

		
((c = a + b))
		
	
Slika 29. - Primer procene vrednosti algebarskog, uvođenjem skripte u 'aritmetički kontekst' (preko "dupliranih zagrada") - verzija 2.

.... međutim, u očima većine 'pisaca skripti', prvi način je intuitivniji.

Pored opcija koje su prikazane, takođe postoji mogućnost da se vrednost izraza računa preko komande expr: *

		
a=10
b=15
c=$(expr $a + $b)
		
	
Slika 30. - Primer procene vrednosti algebarskog izraza preko eksternog programa.

.... što znači (u širem kontekstu), da sličan 'obrazac razmišljanja' možete koristiti ukoliko je potrebno da u shell skriptama obrađujete podatke preko programa koje ste sami pisali. *

* Da pojasnimo: program expr (koji služi za procenu vrednosti algebarskih izraza), praktično je "uobičajena opcija", ali, u pitanju je nezavisni program koji tipično dolazi uz većinu GNU/Linux distribucija tj. nije u pitanju interna komanda iz shell okruženja (što naravno znači da se umesto programa expr može koristiti i "neki drugi" program).

Operatori poređenja i logičke operacije

Za početak, pogledajmo standardno if grananje u C-u ....

		
if (a > o) {
	printf("Vrednost je pozitivna.");
}
		
	
Slika 31. - Primer grananja u programskom jeziku C.

.... koje ćemo uporediti sa odgovarajućom shell sintaksom za proveru uslova (koja praktično obavlja isti zadatak):

		
if [ $a -gt 0 ]; then
	echo "Vrednost je pozitivna."
fi
		
	
Slika 32. - Primer osnovnog grananja u shell skriptama.

Prva 'pomisao' je (najverovatnije): grananja u shell programima se zapisuju slično kao u C-u, "i samo se koriste drugačije zagrade".

Međutim (iako grananja u shell skriptama jesu 'vizuelno slična' grananjima u C-u), iza svega stoji ponešto drugačiji pristup.

Za proveru uslova u shell skriptama, zapravo se koristi ugrađena komanda test .... *

		
test uslov; then komanda
		
	
Slika 33. - Šema izvršavanja interne komande test (u pitanju je komanda koja je ugrađena u shell okruženje).

.... koja se izvršava po sledećem principu: ako je uslov (koji je kao argument predat komandi test) - tačan, pokreće se "komanda" (koja je takođe predata kao argument).

Negde u toku razvoja programa Bash, usvojena je (to jest, implementirana) - uprošćena sintaksa za komandu test ....

		
[ uslov ]; komanda
		
	
Slika 34. - Skraćeni zapis interne komande test.

.... i takva sintaksa (uz ponešto dorade), postala je i deo sintakse za if grananja (kao što smo već videli).

Unutar komande test u shell skriptama (ili, praktičnije - unutar uslova u if grananjima), koriste se i posebni operatori poređenja (u jednom od prethodnih primera koristili smo operator -gt, sa značenjem "veće od", a ostale operatore prikazujemo na slici ispod):

		
# bash/test   C-ovski ekvivalent
-eq           ==   # EQual (jednako)
-gt           >    # Greater Than (veće od)
-ge           >=   # Greater than or Equal (veće ili jednako)    
-lt           <    # Less Than (manje od)
-le           <=   # Less than or Equal (manje ili jednako)
		
	
Slika 35. - Interni operatori poređenja u okviru komande test.

Sa navedenim operatorima dodatno ćemo se upoznati u nešto kasnijim poglavljima, preko primera (videćemo i kako se definišu složeni uslovi), ali, prvo ćemo se ukratko osvrnuti na različite načine za dodelu vrednosti promenljivama.

Sa jedne strane, eksplicitno zadavanje vrednosti je svakako zanimljivo i korisno samo po sebi (i pre svega neophodno, u brojnim situacijama), ali, postoji i mogućnost da se promenljivoj dodeli rezultat izvršavanja određenog programa, a takođe postoji mogućnost učitavanja (sadržaja) datoteka u promenljive ....

Učitavanje datoteka i prosleđivanje rezultata izvršavanja komandi u promenljive

Za početak, razmotrićemo jednostavan primer.

Komanda cat - za koju smo više puta pomenuli da se uglavnom koristi za ispis sadržaja tekstualnih datoteka u konzoli, ovoga puta biće upotrebljena shodno osnovnoj nameni (spajanje sadržaja datoteka), ali - izlaz komande biće učitan u promenljivu:

		
#!/bin/bash

# Ukoliko su datoteke na istoj putanji
# kao skripta, putanje do datoteka mogu se
# navesti na sledeći način:

datoteka1=./proba1
datoteka2=./proba2
datoteka3=./proba3

spojene_datoteke=$(cat $datoteka1 $datoteka2 $datoteka3)

echo $spojene_datoteke
		

	
Slika 36. - Jednostavan primer prosleđivanja rezultata izvršavanja programa u promenljivu.

U svojstvu primera koji je za nijansu kompleksniji, prikazaćemo pajpovanje komande date u komandu awk, * zarad izdvajanja trenutnog vremena (pri čemu se rezultat takođe čuva preko promenljive):

		
#!/bin/bash

vreme=$(date | awk ' { printf("%s\n", $4) } ')
echo $vreme
		
	
Slika 37. - Složeniji primer prosleđivanja rezultata izvršavanja programa u promenljivu.

* .... uz 'blago podsećanje' na to da sama komanda date omogućava upotrebu argumenata, preko kojih se može ispisati (samo) trenutno vreme (potrudite se da sami pronađete navedene argumente). :)

Osvrnimo se i na nekoliko praktičnih primera (koje smo ranije najavili), koji dodatno prikazuju korišćenje UNIX komandi u shell skriptama:

		
#!/bin/bash

korisnik=$(whoami)
operativni_sistem=$(uname)
aktivni_direktorijum=$(pwd)

echo "Korisnički nalog: $korisnik"
echo "Operativni sistem: $operativni_sistem"
echo "Aktivni direktorijum: $aktivni_direktorijum"
		
	
Slika 38. - Nekoliko praktičnih primera prosleđivanja rezultata izvršavanja programa u promenljive.

Upis u datoteke i čitanje iz datoteka

Po potrebi, sadržaj određene promenljive može se proslediti u datoteku, na način koji je čitaocima (verujemo) dobro poznat od ranije.

		
#!/bin/bash

echo $spojene_datoteke > /putanja/nova_datoteka.txt
		

	
Slika 39. - Upis sadržaja promenljive u datoteku, preko redirekcije.

Naravno, u pitanju je 'redirekcija' (korisna tehnika sa kojom smo se susreli još u uvodnom članku).

Učitavanje datoteka se takođe može obaviti na idejno sličan način, ali, uz korišćenje nešto drugačije sintakse (koja je, srećom, vrlo jednostavna za razumevanje):

		
#!/bin/bash

a=$(</home/korisnik_1/datoteka.txt)
		

	
Slika 40. - Čitanje sadržaja datoteke i upis u promenljivu, preko redirekcije.

Gornji primer (budući da smo ionako u odeljku koji se tiče promenljivih u shell skriptama) - može se uopštiti:

		
#!/bin/bash

datoteka=/home/korisnik_1/datoteka.txt

a=$(<$datoteka)
		

	
Slika 41. - Primer sa prethodne slike, zapisan na pregledniji način.

Prava 'poenta' poslednja dva primera je sledeća: ne mora se koristiti komadna cat zarad učitavanja sadržaja datoteka u promenljive (u smislu, ne mora se pisati: a=$(cat $datoteka) - čime se izbegava poziv dodatne komande).

Ostale praktične primere upotrebe promenljivih, prikazaćemo u narednim odeljcima.

Nizovi (liste)

Nizovi u shell skriptama najčešće se definišu metodom implicitne deklaracije (pogotovo u situacijama kada korisnici sami kreiraju nizove) ....

		
#!/bin/bash

niz[0]=10
niz[1]=12
niz[2]=15
		

	
Slika 42. - Primer implicitne deklaracije (elemenata) niza.

.... ali (sasvim očekivano), postoje i drugi načini, kao što je eksplicitna deklaracija ....

		
#!/bin/bash

declare -a niz
		
	
Slika 43. - Primer eksplicitne deklaracije niza.

Argument "-a" označava niz ("array").

.... ili, metoda složene dodele, koja podrazumeva istovremenu deklaraciju i inicijalizaciju celog niza:

		
#!/bin/bash

niz=(1 2 3 4 5)
		
	
Slika 44. - Primer istovremene (implicitne) deklaracije i inicijalizacije niza.

Napomena: Primetite da nema zareza između elemenata (međutim, sintaksa je inače veoma nalik (tipičnoj) "ad hoc" deklaraciji/inicijalizaciji niza u JavaScript-u ili Python-u).

Pristup pojedinačnom elementu obavlja se na prepoznatljiv način (ali, uz korišćenje 'vitičastih' zagrada u određenim okolnostima):

		
#!/bin/bash

niz[0]=15
echo ${niz[0]}
		
	
Slika 45. - Primer pristupa elementu niza.

Očitavanje dužine niza obavlja se na sledeći način:

		
#!/bin/bash

d=${#niz[*]}
		
	
Slika 46. - Primer očitavanja dužine niza.

Uklanjanje pojedinačnog elementa, ili celog niza, obavlja se preko komande unset:

		
#!/bin/bash

unset niz[4] # uklanjanje petog elementa
unset niz    # uklanjanje celog niza
		
	
Slika 47. - Primer uklanjanja pojedinačnog elementa niza i (potom) celog niza.

Obilazak strukture niza tipično se obavlja preko for petlje (što ćemo sagledati na primerima u nastavku, u odeljku koji je posvećen for petljama).

Shell promenljive (environment variables)

Pored promenljivih koje korisnici mogu sami definisati u okviru skripte, postoje i promenljive koje se ('globalno') prepoznaju u okviru određenog shell okruženja, a mogu se koristiti i u korisničkim skriptama (koje se pokreću u datom shell okruženju).

Na određenim mestima u literaturi, pominje se termin "ugrađene promenljive", i (naravno), postoje ugrađene promenljive u shell okruženjima, ali, većina promenljivih na koje se odnosi odrednica "environment variables", zapravo su promenljive koje se (automatski) kreiraju preko eksternih programa (a takođe se neretko radi i o promenljivama koje kreiraju sami korisnici).

Budući da su shell promenljive idejno slične globalnim promenljivama u C-u (i drugim srodnim jezicima) - identifikatori shell promenljivih tipično se pišu uz upotrebu tzv. "allcaps" notacije (svako slovo u identifikatoru je veliko slovo):

		
#!/bin/bash

echo "Shell: $SHELL"
echo "Terminal: $TERM"
# --------------------------------------
echo "Sistemske putanje: $PATH"
# pažnja: promenljiva PATH može
# sadržati veliki broj putanja
# --------------------------------------
echo "Home direktorijum: $HOME"
echo "Aktivni direktorijum: $PWD"
echo "Prethodni aktivni direktorijum: $OLDPWD"
echo "Verzija programa Bash: $BASH_VERSION"
echo "Naziv računara u mreži: $HOSTNAME"
		
	
Slika 48. - Primeri ('globalnih') shell promenljivih (environment variables).

Gornja skripta je "samoobjašnjujuća" (uz svaku 'globalnu' promenljivu iz shell okruženja stoji odgovarajući opis), a što se tiče konkretnih vrednosti koje se odnose na vašu instalaciju Linux-a (ili nekog drugog "nix" sistema) - napišite skriptu i pokrenite je. :)

Kontrola toka

U shell skriptama (slično kao u C-olikim i mnogim drugim programskim jezicima), pojavljuju se sledeći tokovi izvršavanja instrukcija:

  • linearno (tj. uzastopno) izvršavanje naredbi
  • grananja
  • petlje

Naravno, moguće su i kombinacije.

Prvo ćemo se upoznati sa linearnim izvršavanjem naredbi.

Linearno izvršavanje naredbi

Uzmimo za primer da određeni program (koji koristimo), ostavlja konfiguracione datoteke u home direktorijumu, * zbog čega postoji potreba za povremenim uklanjanjem datoteka ("koje nismo tražili"), pri čemu, naravno, želimo da uklanjanje datoteka izvedemo na što jednostavniji način.

U situaciji koju smo opisali, shell skripte tipično predstavljaju pravo rešenje. **

* Autori ozbiljnijih programa obično vode računa o tome da ne smeštaju "sve i svašta" u home direktorijum (rekli bismo da većina poštuje i specifikaciju XDG o kojoj smo ranije pisali), ali, naravno - ima izuzetaka.

Takođe (da pomenemo, "ipak"/"za svaki slučaj"): datoteke se mogu uklanjati samo ukoliko znamo da uklanjanje datoteka neće ugroziti funkcionisanje instaliranih programa (i pogotovo - funkcionisanje samog operativnog sistema).

** Skripta koju ćemo prikazati ispod služi za uklanjanje fiktivnih datoteka, međutim, dovoljno je samo da navedemo realna imena datoteka (koje je potrebno uklanjati periodično) - i skripta će postati krajnje svrsishodna.

(Da sve bude 'još bolje', preko tzv. cron tabela, o kojima ćemo pisati u poslednjem poglavlju, moguće je udesiti i da se skripta pokreće automatski, u određeno doba dana i sl.)

Ukoliko su preduzete sve mere predostrožnosti, možemo napisati sledeću jednostavnu skriptu:

		
#!/bin/bash

# Uklanjanje datoteka koje ostaju posle
# pokretanja komande xyz
	
echo "----------------------------------"
echo "Uklanjanje suvišnih datoteka:"
echo "----------------------------------"

rm ~/.xyzconf
rm ~/.xyzerrorlog
rm ~/.xyzhistory

echo "Sledeće datoteke:"
echo "    ~/.xyzconf"
echo "    ~/.xyzerrolog"
echo "    ~/.xyzhistory"
echo ".... uspešno su uklonjene."
echo "----------------------------------"
		
	
Slika 49. - Primer skripte za uklanjanje nepotrebnih datoteka (primer prikazuje linearno izvršavanje naredbi).

Kao što vidimo:

  • u skriptama se mogu pokretati komande (u gornjem primeru, komanda je rm)
  • preko komande echo, obavlja se ispis u konzoli

(Nastavljamo dalje ....)

Grananja (if, case)

Pošto smo se ranije upoznali sa time "odakle 'ćoškaste zagrade' u if-ovima u shell okruženju", upoznaćemo se detaljnije sa sintaksom za zapisivanje grananja u shell skriptama, uz "povlačenje paralela" u odnosu na C i Python.

Nešto kasnije upoznaćemo se i sa petljama (takođe uz poređenje sa petljama iz C-a i Python-a), a pošto smo u gornjem naslovu naveli "grananja" (u množini), mislimo na to da u shell skriptama postoje: i if grananja, i case grananje (konstrukcija nalik na switch u C-u).

if-else-elif-fi grananje

Za početak, pogledajmo primer 'običnog' if grananja (ispituje se da li je vrednost a veća od 10):

		
#!/bin/bash

a=10

if [ $a -gt 10 ]; then
	poruka="Vrednost a je veća od 10."
else
	poruka="Vrednost a nije veća od 10."
fi

echo "${poruka}"
		
	
Slika 50. - Jednostavan primer if grananja.

Ukoliko else blok postoji, 'true grana' počinje rezervisanom reči then i završava se pojavom rezervisane reči else, dok se u suprotnom 'true grana' završava rezervisanom reči fi (koja u svakom slučaju stoji na kraju if bloka).

Višestruka grananja (slično kao u Python-u), tipično se izvode preko rezervisane reči elif (ponovo ćemo se poslužiti jednostavnim primerom koji predstavlja 'ispis dana u nedelji, shodno rednom broju'):

		
#!/bin/bash

dan=5
uslov=true

# Višestruko grananje preko konstrukcije elif:

if [ $dan = 1 ]; then
	poruka="Ponedeljak"
elif [ $dan = 2 ]; then
	poruka="Utorak"
elif [ $dan = 3 ]; then
	poruka="Sreda"
elif [ $dan = 4 ]; then
	poruka="Četvrtak"
elif [ $dan = 5 ]; then
	poruka="Petak"
elif [ $dan = 6 ]; then
	poruka="Subota"
elif [ $dan = 7 ]; then
	poruka="Nedelja"
else
	poruka="Dan nije definisan"
	uslov=false
fi

# Uobičajeno grananje (if-else):

if [ $uslov = true ]; then
	echo "Dan u nedelji: ${poruka}."
else
	echo "${poruka}"
fi
		
	
Slika 51. - Složeniji primer grananja (u kome se koristi i elif konstrukcija). U praktičnom smislu, primer podseća na switch grananja u C-u.

U pitanju je kod koji je sam po sebi krajnje adekvatan, međutim, budući da u shell skriptama (za razliku od Python-a), postoji i konstrukcija nalik na switch grananja u C-olikim jezicima (doduše, pod drugačijim - ali dobro poznatim nazivom), 'mnogostruka grananja' se često mogu zapisati na elegantniji način (što ćemo razmotriti na primeru istog algoritma) ....

case-esac grananje

Slično kao i switch u C-olikim jezicima, case grananje u shell skriptama omogućava pregledniju organizaciju višestrukih uslova - onda kada jeste moguće navesti višestruke uslove preko konstrukcije case.

Uzmimo (ponovo) primer sa ispisom dana u nedelji (shodno unetom rednom broju):

		
#!/bin/bash

dan=5
uslov=true

# Switch koji se koristi
# umesto višestrukog grananja
# iz prošlog primera:

case $dan in
	1) poruka="Ponedeljak" ;;
	2) poruka="Utorak"     ;;
	3) poruka="Sreda"      ;;
	4) poruka="Četvrtak"   ;;
	5) poruka="Petak"      ;;
	6) poruka="Subota"     ;;
	7) poruka="Nedelja"    ;;
	*) poruka="Dan nije definisan."
	   uslov=false
	;;
esac

# Primer uobičajenog grananja (if-else):

if [ $uslov = true ]; then
	echo "Dan u nedelji: ${poruka}."
else
	echo "${poruka}"
fi
		
	
Slika 52. - Primer case grananja u shell skriptama (konstrukcija koja je, u praktičnom smislu, isto što i switch iz C-a).

Na prethodnoj slici smo prikazali kod koji se može realizovati preko case grananja, ali (kao što smo nagovestili), postoje i situacije u kojima se case grananje ne može izvesti.

Nije moguće (recimo), koristiti višestruke uslove ....

		
case $a in
	$a -ge 1 -a $a -le 5) promenljiva=$vrednost_1 ;;
	$a -ge 6 -a $a -le 7) promenljiva=$vrednost_2 ;;
	$a -ge 8 -a $a -le 10) promenljiva=$vrednost_3 ;;
	*) promenljiva=$vrednost_4 ;;
esac
		
	
Slika 53. - Primer 'slučajeva' (praktično - uslova), koji se ne mogu pojaviti u case grananjima.

.... i stoga - u situacijama kakve prikazuje primer sa gornje slike - potrebno je koristiti konstrukciju if-else-elif-fi.

Praktičan primer skripte koja koristi grananje

Sa grananjem u shell skriptama još bolje ćemo se upoznati kroz konkretan primer (iz svakodnevne prakse), koji može dobro poslužiti korisnicima laptop računara (a verujemo da tematika može biti zanimljiva i ostalim čitaocima).

Linux čuva podatke o statusu i kapacitetu baterije * preko sledeće dve datoteke:

  • /sys/class/power_supply/BAT0/status - status baterije (navešćemo u nastavku šta predstavljaju različiti statusi)
  • /sys/class/power_supply/BAT0/capacity - kapacitet baterije u procentima (s tim da znak % nije zapisan u datoteci)

Podaci jesu dostupni, ali - ako je potrebno da sve bude formatirano i prikazano na pregledan i dopadljiv način - moramo se dodatno potruditi.

Da objasnimo prvo šta označavaju različiti statusi baterije (koji se mogu pročitati iz datoteke status):

  • "Not charging" - ispravljač nije priključen i baterija se prazni
  • "Charging" - ispravljač je priključen i baterija se puni
  • "Full" - ispravljač je priključen i baterija je u potpunosti napunjena
  • "Not Charging" - ispravljač je priključen, ali, baterija se ne puni (česta situacija do koje dolazi kada se ispravljač priključi onda kada je baterija, koja se do tada praznila, napunjena na preko 90% kapaciteta)

Pojam kapaciteta (u trenutnom kontekstu), lakši je za razumevanje: u datoteci capacity uvek je zapisana određena vrednost, bez obzira na to da li je ispravljač priključen ili nije (tj. bez obzira na to da li se baterija prazni ili puni i sl).

* Direktorijumi i datoteke koje smo naveli, odnose se na (tipičnu) situaciju kada na laptopu postoji jedna baterija, međutim, ukoliko na laptopu postoji i druga baterija, Linux će kreirati i direktorijum BAT1 (sa datotekama status i capacity (i sa ostalim datotekama)).

Pošto smo upoznati sa tehnikalijama, možemo napisati skriptu u celosti:

		
# ---------------------------------------------------------
#!/bin/bash
# ---------------------------------------------------------
# Čitanje podataka:

bat_stat=$(</sys/class/power_supply/BAT0/status)
bat_cap=$(</sys/class/power_supply/BAT0/capacity)
# ---------------------------------------------------------
# Razmatranje svih mogućih statusa:

if [ "$bat_stat" = "Charging" ]; then
	status="Ispravljač je uključen."
	poruka="Trenutni kapacitet baterije: ${bat_cap}%."
elif [ "$bat_stat" = "Full" ]; then
	status="Ispravljač je uključen."
	poruka="Baterija je potpuno napunjena."
elif [ "$bat_stat" = "Not charging" ]; then
	status="Ispravljač je uključen - ali se baterija ne puni."
	poruka="Trenutni kapacitet baterije: ${bat_cap}%."
else
	# status="Discharging" - ako se nije
	# aktivirao nijedan od prethodnih if-ova
	status="Ispravljač je isključen."
	poruka="Trenutni kapacitet baterije: ${bat_cap}%."
fi
# ---------------------------------------------------------
# Ispis poruke (koji se obavlja u svim okolnostima)

echo "$status $poruka"
# ---------------------------------------------------------
# Dodatni ispis (ukoliko je ispravljač isključen,
# a kapacitet baterije je nizak):

if [ $bat_cap -le 25 ] && [ "$bat_stat" = "Discharging" ]; then
	echo "PAŽNJA: Nizak kapacitet baterije!\n"
	echo "Potrebno je uključiti ispravljač."
fi
# ---------------------------------------------------------
		
	
Slika 54. - Praktičan primer skripte iz svakodnevne prakse (skripta očitava stanje baterije na laptop računarima i koristi if grananja).

Primer koji smo prikazali je dovoljno zanimljiv sam po sebi (verujemo da je tako), međutim, svakako se može staviti u kontekst u kome postaje - još zanimljiviji.

U uvodnom članku o GNU/Linux distribucijama pomenuli smo da različita desktop okruženja i (pogotovo) menadžeri prozora, mogu - zarad prikaza sistemskih parametara - koristiti skripte i programe koje korisnici kreiraju samostalno.

Osnovna ideja je da se parametri očitavaju periodično (recimo, na svakih 1s) i, u takvim okolnostima, jedan od parametara za prikaz može biti - formatirani ispis u vezi sa stanjem baterije.

Međutim, s obzirom na to da je ispis koji smo spremili u prethodnom primeru prilično opsežan (prosto rečeno - mnogo teksta za statusnu liniju :)), ispis se može stilizovati upotrebom specijalnih znakova koji - umesto tekstualne poruke - prikazuju simbol za bateriju (kada je ispravljač isključen), ili simbol za utikač (kada je ispravljač uključen), a mogu se koristiti i različite boje za označavanje elemenata i sl:

⚠️🔋 7% !!!
🔋80% 🔌27%

Na slici ispod možete videti i praktičan primer upotrebe (a prikazaćemo i dodatne primere u narednom odeljku članka).

Ali - "to nije sve" - može se osmisliti i mehanizam za čuvanje prethodnog stanja, što omogućava da se trenutno stanje poredi sa prethodnim (pri svakom očitavanju), što nadalje omogućava da se registruju trenuci kada korisnik uključi ili isključi ispravljač (na šta se može odreagovati ispisivanjem odgovarajuće poruke preko posebnih programa za ispis tekstualnih poruka u prozorima). *

alt
Slika 55. Primeri izvršavanja programa za ispis servisnih poruka u prozoru (na prvom delu slike, izlaz komande cal pajpovan je u program dunst; na preostale dve slike, očitava se stanje baterije (preko DIY skripte), i prepoznaju se trenuci kada korisnik isključi ili uključi ispravljač na laptop-u).

* U ovom trenutku, naša preporuka je program Dunst.

Nekoliko primera izvršavanja možete videti na gornjoj slici, a da biste mogli sami isprobavati kako ispisivanje poruka funkcioniše, instalirajte program i unesite u konzolu sledeću komandu:

dunstify "Dobar dan! :)"

U gornjem desnom uglu ekrana (u obojenom prozoru), pojaviće se poruka koju ste uneli.

Petlje (while, for)

Petlje u shell skriptama su idejno slične petljama u 'uobičajenijim' programskim jezicima, sintaksa podseća na if grananja u shell skriptama, a 'dodatak' je specifična konstrukcija do-done, koja predstavlja graničnik tela petlje.

while petlja

Osnovni princip funkcionisanja while petlji u shell skriptama možemo sagledati preko sledećeg primera (ispis brojeva od 1 do 10):

		
#!/bin/bash

a=1

while [ $a -le 10 ]
do
	echo "a=${a}"
	a=$((a+1))
done
		
	
Slika 56. - Primer jednostavne while petlje.

U while i for petljama, rezervisane reči do i done su praktično "vitičaste zagrade".

Kao što smo ranije nagovestili, kontrolne strukture se takođe mogu i ugnežđavati, pa tako (recimo) while petlja u narednom primeru prolazi kroz vrednosti od 1 do 10 i ispituje (i ispisuje), za svaku vrednost, da li je broj paran ili neparan:

		
#!/bin/bash

a=1

while [ $a -le 10 ]
do
	o=$(($a%2)) # ostatak

	if [ $o = 0 ]; then
		echo "a=${a}; broj je paran"
	else
		echo "a=${a}; broj je neparan"
	fi

	a=$(($a+1))
done
		
	
Slika 57. - Primer 'ugnežđavanja' unutar while petlje.

Osvrnućemo se takođe na to da se u while petljama (koje se koriste u shell skriptama), prilično često javlja "motiv" beskonačnih petlji.

U pitanju je praktičan (iako ne baš previše elegantan), način da se realizuje "program koji se ne isključuje", tipično uz upotrebu sledeća dva mehanizma:

  • funkcija sleep zaustavlja izvršavanje skripte na određeno vreme, u svakom koraku petlje (čime se praktično definiše interval u kome se petlja ponavlja)
  • if grananje, uz funkciju break, zaustavlja petlju (to jest, celu skriptu), ukoliko se pojave okolnosti u kojima treba zaustaviti izvršavanje skripte

U donjem primeru, petlju - koja praktično predstavlja beskonačnu petlju - ipak ćemo realizovati preko uobičajenog uslova.

Praktičan primer skripte koja koristi petlju

U novom primeru, prepoznaje se trenutak kada kapacitet baterije (laptop računara), 'padne' ispod 25%:

		
#!/bin/bash

uslov=true

while [ $uslov = true ]
do
    # spisak naredbi koje se mogu izvršavati
    # ako je kapacitet baterije veći od 25%
    # naredba 1
    # naredba 2
    # ....
    # naredba n
    
	bat_cap=$(</sys/class/power_supply/BAT0/capacity)
    
    if [ $bat_cap -le 25 ]; then
        uslov=false
        echo "-------------------------------------"
        echo "Prekida se izvršavanje programa"
        echo "zbog nedovoljnog kapaciteta baterije."
    else
        echo "Kapacitet baterije je ($bat_cap%) >= 25%"
    fi

    sleep 1
done
		
	
Slika 58. - Primer korisničke skripte sa beskonačnom petljom i uslovom za izlazak (skripta proverava stanje baterije laptop računara i reaguje kada kapacitet padne ispod 25%).

Skripta se pokreće na svakih 1s, i zaustavlja se ukoliko promenljiva uslov dobije vrednost true (do čega dolazi ako se ustanovi da ispravljač nije priključen i pri tom je kapacitet baterije manji od 25%).

Takođe: verujemo da se u ovom trenutku pitate da li će se kod izvršavati pravilno(?!) - i ne želite da čekate više desetina minuta, dok se baterija laptopa 'legitimno' isprazni - pa da tek onda saznate. :)

Za isprobavanje skripte: napravite datoteku kapacitet (u istom direktorijumu u kom je skripta), u prvu liniju unesite brojčanu vrednost, prepravite (privremeno) glavnu skriptu na sledeći način ....

		
# .... prethodne naredbe	
	
# bat_cap=$(</sys/class/power_supply/BAT0/capacity)
bat_cap=$(<./kapacitet)
	
# ostatak skripte ....
		
	
Slika 59. - Izmenjeni parametri iz prethodne skripte (u izmenjenom stanju, skripta omogućava lakše testiranje).

.... potom pokrenite skriptu - i menjajte usput vrednosti u datoteci kapacitet (u nekom trenutku, unesite vrednost <= 25).

Ako skriptu pokrećete preko menadžera prozora ....

GNU/Linux 04_01
Slika 60. - Primer korišćenja menadžera prozora pri pokretanju skripte.

.... moći ćete da sagledate ceo proces na jednoj radnoj površini. *

Opsežniji i zanimljiviji primer while petlje koja se "vrti ukrug" (beskonačna petlja), videli smo još u uvodnom članku (link vodi direktno do primera while petlje za ispis sistemskih parametara na naslovnoj traci menadžera prozora). **

* Usput: na slici (ponovo) možete videti i kako izgleda kada se (ponešto izmenjena i dopunjena) skripta za očitavanje baterije, poveže sa (drugom) skriptom, koja prikazuje sistemske parametre na naslovnoj traci menadžera prozora (na slici je menadžer prozora dwm, a preko zelenih ikona prikazan je status baterije ili ispravljača).

** Nadamo se da vam je (već sada) navedeni primer iz uvodnog članka razumljiv u potpunosti. :)

for petlja

For petlje u shell skriptama koriste princip "iteracije kroz listu" (slično kao for petlje u Python-u) ....

		
#!/bin/bash

niz=(10 20 30 40 50)

for element in ${niz[@]}
do
	echo "e = ${element}"
done
		
	
Slika 61. - Primer for petlje koja prolazi kroz elemente niza.

.... ali, vidimo da je potrebno vrlo precizno navesti sintaksu za obraćanje nizu (za razliku od JS-a i Python-a koji omogućavaju vrlo jednostavan način obraćanja nizovima).

Za 'najuobičajenije' for petlje, koje se izvršavaju u rasponu "od-do", postoji i skraćeni način definisanja 'liste koju for petlja treba da obiđe':

		
#!/bin/bash

for element in {1..10}
do
	echo "e = ${element}"
done
		
	
Slika 62. - Primer for petlje koja se izvršava u koracima, "od 1 do 10".

Ukratko o funkcijama u shell skriptama

Kao što smo već nagovestili, shell programi takođe omogućavaju pokretanje funkcija, sa sintaksom koja je (ovoga puta) relativno slična sintaksi iz C-olikih jezika (uz jedan zanimljiv izuzetak, na koji ćemo se uskoro osvrnuti).

Opšta šema je sledeća:

		
naziv_funkcije () {
	komande
}
		
	
Slika 63. - Opšta šema funkcije u shell okruženju.

Kao početni primer može poslužiti veoma jednostavna "hello world" funkcija, koja se zapisuje (i poziva) na sledeći način ....

		
#/bin/bash

pozdrav() {
	echo "Dobar dan! :)"
}

pozdrav
		
	
Slika 64. - Primer veoma jednostavne funkcije koja ispisuje pozdravnu poruku.

.... pri čemu se u terminalu (očekivano) dobija ispis ....

		
Dobar dan! :)
		
	
Slika 65. - Rezultat izvršavanja funkcije pozdrav.

Što se tiče (prethodno najavljene) 'zanimljivosti' u sintaksi shell funkcija - u pitanju je predavanje argumenata.

Naime, u shell funkcijama ne postoji "C-oliki" način definisanja parametara "u zagradi" (iako se same zagrade navode uz identifikator funkcije).

Umesto uobičajenog pristupa, parametri se označavaju rednim brojevima - tako da 'redni broj parametra' odgovara redosledu predavanja argumenata pri pozivu funkcije: pozicioni parametar $1 odgovara prvom predatom argumentu, parametar $2 odgovara drugom argumentu .... parametar $9 odgovara devetom predatom argumentu.

$9 je 'poslednji mogući' pozicioni parametar.

Ukoliko (za primer) definišemo funkciju koja pronalazi i ispisuje veću od dve unete vrednosti ....

		
veci_od_dva() {
	if [ $1 -ge $2 ]; then
        echo "Broj $1 je veći od broja $2 (ili jednak)."
    else
        echo "Broj $2 je veći od broja $1."
    fi
}
		
	
Slika 66. - Primer jednostavne funkcije koja vraća veću od dve unete vrednosti.

.... funkcija se poziva na sledeći način ....

		
#/bin/bash
	
# definicija funkcije veci_od_dva (sa slike #66),
# izostavljena je zarad preglednosti.

# poziv funkcije:
veci_od_dva 12 15
		
	
Slika 67. - Primer pozivanja shell funkcije veci_od_dva.

.... nakon čega se dobija sledeći ispis:

		
Broj 15 je veći od broja 12 (ili jednak).
		
	
Slika 68. - Primer ispisa nakon izvršavanja funkcije veci_od_dva.

U sledećem poglavlju, upoznaćemo se još i sa time kako shell skripte mogu obrađivati argumente komande linije (a u narednim člancima, biće i 'konkretnijih'/zanimljivijih primera shell funkcija) ....

Nekoliko dodatnih primera shell skripti

.... iz svakodnevne prakse

Uvodno izlaganje o shell skriptama završićemo * uz osvrt na još nekoliko zanimljivih tehnikalija ("koje dobro dođu").

* Nije kraj članka (kao što smo najavili, posle shell skripti sledi osvrt na komandu watch i cron tabele).

Obrada korisničkog unosa

Ukoliko je potrebno da korisnik ("ručno") unese tekst u skriptu, tekst se može uneti preko terminala (pogledajmo primer):

		
#!/bin/bash

echo "---------------------------------------------------"
echo "Kreiranje novog direktorijuma na trenutnoj putanji:"
echo "---------------------------------------------------"

read -p "Unesite naziv direktorijuma: " novi_dir

pwd=$(pwd) # rezultat izvršavanja
           # komande pwd

putanja="$pwd/$novi_dir"

if [ -d "$putanja" ]; then
	echo "Direktorijum već postoji!"
else
	mkdir $putanja
	echo "Novi direktorijum: $novi_dir"
	echo "Apsolutna putanja: $putanja"
	echo "Direktorijum je kreiran."
fi
		
	
Slika 69. - Primer skripte koja korisnicima omogućava da unesu podatke preko komande read (koja se pokreće u terminalu).

Kroz primer, upoznali smo se sa komandom read, koja omogućava unos podataka u okviru shell okruženja.

Koristili smo argument -p (prompt), a inače se po potrebi može navesti i argument -s ("silent"), * što je korisno pri učitavanju lozinki.

		
read -ps "Unesite lozinku: " lozinka
		
	
Slika 70. - Primer učitavanja lozinke, preko komande read.

* Umesto znakova koje korisnik unosi preko tastature, na izlazu se pojavljuju znaci *.

U prvom primeru pojavljuje se i komanda za očitavanje trenutnog direktorijuma (pwd), koju smo iskoristili za formiranje apsolutne putanje novog direktorijuma (putanja se pojavila u svojstvu argumenta komande mkdir).

Predavanje argumenata preko terminala

Ukoliko je potrebno da skripta učita argumente komande linije, obrada se obavlja na sledeći način:

- Pri pozivu skripte, argumenti se predaju isto onako kako se argumenti predaju npr. programima koji su pisani u C++-u i sl:

		
$ ./skripta.sh 10 12
		
	
Slika 71. - Primer pokretanja shell skripte kojoj se prosleđuju argumenti preko terminala.

- Argumenti komande linije prihvataju se preko 10 specijalnih promenljivih, to jest, tzv. pozicionih parametara * u rasponu od $0 do $9:

		
#/bin/bash

# pozvaćemo funkciju veci_od_dva
# koju smo definisali u prethodnom poglavlju:

veci_od_dva $1 $2
		
	
Slika 72. - Primer shell funkcije koja prihvata argumente komandne linije.

* Parametar $0 odgovara nazivu pokrenute skripte ("skripta.sh"), parametar $1 odgovara prvom predatom argumentu ("10"), parametar $2 odgovara drugom predatom argumentu ("12") i sl ....

Pokretanje skripte skripta.sh, proizvodi sledeći ispis:

		
Broj 12 je veći od broja 10 (ili jednak).
		
	
Slika 73. - Primer izlaza u konzoli koji se dobija nakon pokretanja skripte skripta.sh (sa prethodne slike).

Formatiranje izlaza preko komande printf

Ukoliko je potrebno formatirati tekst na precizan način, moguće je (u shell okruženjima Bash i Zsh), koristiti dobro poznatu komandu printf (doduše, uz ponešto izmenjenu sintaksu): *

		
#!/bin/bash

a=10
b=15

printf "%d + %d = %d" $a $b `expr $a + $b`

# izlaz: 10 + 15 = 25
		
	
Slika 74. - Primer formatiranja izlaza preko komande printf.

* Jeste malo drugačije u odnosu na printf iz C-a, ali, bez brige - navići ćete se. :)

Automatsko pokretanje procesa preko komande watch

Na UNIX-olikim operativnim sistemima, jednostavno periodično pokretanje ("drugih") procesa u konzoli obavlja se preko programa watch, prema sledećem opštem obrascu:

		
watch -n interval komanda (argumenti)
		
	
Slika 75. - Šema izvršavanja komande watch.
  • interval - interval za pokretanje ("unutrašnje") komande
  • komanda - komanda koja se pokreće periodično
  • argumenti - argumenti koji se mogu predavati unutrašnjoj komandi (nije obavezno predavati argumente i nije obavezno da određena interna komanda prepoznaje dodatne argumente)

Usput: program watch je jednostavniji od dva mehanizma za automatsko pokretanje procesa u UNIX-olikim okruženjima.

Razmotrićemo (krajnje tipičan) primer upotrebe komande watch:

		
watch -n 1 free -h
		
	
Slika 76. - Primer izvršavanja komande watch.

Komanda free (poznata iz 2. nastavka), * pokreće se u intervalu od jedne sekunde (-n 1) ** i svaki put kada se proces pokrene - automatski se osvežava prikaz.

Ukoliko se komanda watch navede uz predavanje argumenta -d ("differences"):

		
watch -n 1 -d free -h
		
	
Slika 77. - Primer izvršavanja komande watch - uz markiranje izmena između dva očitavanja.

.... u prikazu će biti označene razlike (tj. promene), između dva 'očitavanja':

* Da se podsetimo ukratko: komada free očitava i ispisuje parametre vezane za zauzeće RAM memorije.

** Ukoliko se ne navede interval, komanda watch pokreće unutrašnju komandu (i ažurira prikaz rezultata), na svake 2 sekunde.

Periodično/redovno pokretanje procesa (cron, crontab)

Pored komande watch, na UNIX-olikim operativnim sistemima postoji i pozadinski proces cron, čija je namena - pokretanje procesa (tj. programa, skripti i drugih pozadinskih procesa), u pravilnim intervalima koje korisnici mogu sami definisati preko posebnih tabela.

Naziv cron potiče od grčke reči "hronos" (anglicizirano - "chronos"), što u prevodu znači vreme, a navedimo takođe i to da je cron 'zvaničniji' mehanizam (u odnosu na komandu watch).

Cron tabele se najčešće koriste za ozbiljnije zadatke kao što je redovno pokretanje skripti za administraciju sistema (ažuriranje, bekap i sl), pri čemu se pristup tabelama obavlja preko sledeće komande: *

		
crontab -e
		
	
Slika 78. - Primer pokretanja komande crontab.

* Argument -e označava poziv za uređivanje tabele ("edit").

Svaki red u cron tabeli - koji predstavlja periodično pokretanje pojedinačnog procesa (eng. "cron job") - definisan je po sledećem obrascu:

		
┌ ╶ ╶ ╶ ╶ ╶ minut         (0-59)
| ┌ ╶ ╶ ╶ ╶ sat           (0-23)
| | ┌ ╶ ╶ ╶ dan u mesecu  (1-31)
| | | ┌ ╶ ╶ mesec         (1-12)
| | | | ┌ ╶ dan u nedelji (0-6) *
| | | | |
* * * * * korisnik komanda
		
	
Slika 79. - Struktura pojedinačnog reda u tabeli crontab.

* Pri označavanju dana u nedelji, koristi se raspon od 0 do 6, ali - nula ne označava ponedeljak, već - nedelju (u pitanju je način označavanja koji je tipičan za anglosaksonsko govorno područje).

U praktičnom smislu: 0 = nedelja, 1 = ponedeljak, 2 = utorak .... 5 = petak, 6 = subota.

Osvrnimo se na konkretan primer ....

		
0 * * * * korisnik_1 /home/korisnik_1/.skripte/glavni_bekap.sh
		
	
Slika 80. - Primer: cron job koji se pokreće na svaki pun sat.

Prema navedenim podešavanjima: operativni sistem (preko korisničkog naloga korisnik_1), na svaki pun sat pokreće skriptu glavni_bekap.sh (koja se nalazi na navedenoj putanji), ali - pretpostavićemo da (možda) "ne deluje da tako piše u gornjoj tabeli" - i stoga ćemo pojasniti (na jednostavan način, preko dodatnih primera), kako se zadaju vremenski intervali za pokretanje cron zadataka.

Sledeći kod (gotovo istovetan) ....

		
* * * * * korisnik_1 /home/korisnik_1/.skripte/skripta.sh
		
	
Slika 81. - Primer: cron job koji se pokreće na svaki pun minut.

.... definiše da se skripta pokreće na svaki pun minut (programe ili skripte moguće je pokretati samo kada je broj sekundi na sistemskom časovniku "00"), ili, preciznije - skripta se pokreće:

  • svakog meseca
  • svakog dana u mesecu
  • svakog dana u nedelji
  • svakog sata
  • na svaki pun minut

Ali - sa druge strane ....

Bilo koja vrednost koja nije * predstavlja (praktično) faktor ograničenja, i stoga (na primer) sledeći "cron job": 0 * * * * korisnik_1 /home/korisnik_1/.skripte/glavni_bekap.sh - definiše da se navedena skripta pokreće samo onda kada minut (na sistemskom časovniku) ima vrednost 0, što praktično znači - navedena skripta se pokreće na svaki pun sat (upravo onako kako smo videli u prvom primeru).

U nastavku, upoznaćemo se sa time kako se može udesiti da se određena skripta pokrene u određeno vreme (svakog dana, ili samo određenim danima).

Razmotrićemo nekoliko primera koji podsećaju na 'automatizaciju procesa' u mrežnim okruženjima različitih preduzeća.

Ako je potrebno da se određena skripta pokrene svakog dana u određeno vreme, dovoljno je navesti (samo) vreme izvršavanja (za primer ćemo uzeti skriptu koja odjavljuje prijavljene korisnike, nakon isteka radnog vremena).

		
31 16 * * * root /.skripte/logout.sh
		
	
Slika 82. - Primer: cron job koji se pokreće (svakog dana) u 16:31.

Drugi primer biće cron job koji pokreće bekap podataka na nedeljnom nivou (jednom nedeljno, na primer, petkom):

		
35 16 * * 5 root /.skripte/bekap_nedeljni.sh
		
	
Slika 83. - Primer: cron job koji se pokreće svakog petka u 16:31 (to jest - cron job se pokreće samo petkom, u navedeno vreme).

Međutim, ako je potrebno da se bekap obavlja svakog radnog dana, cron job koji je podešen po uzoru na cron job sa slike #82 neće biti od pomoći (budući da je u pitanju pokretanje procesa svakog dana - ne samo radnim danima), a u drugim situacijama, može postojati i potreba za preciznijim definisanjem intervala (recimo, nije potrebno da se određena skripta izvršava svakog minuta, ali, potrebno je da se izvršava "češće od svakog sata" i sl), i stoga je uputno da se upoznamo sa sintaksom koja omogućava (upravo) - dodatno preciziranje.

Definisanje raspona

Ukoliko se umesto jedne vrednosti navede raspon, u obliku početak-kraj (sa crticom između), cron job će se pokretati za svaku celobrojnu vrednost iz raspona.

Na primer, sledeći cron job ....

		
31 16 * * 1-5 root /.skripte/bekap_dnevni.sh
		
	
Slika 84. - Primer definisanja raspona za jedan od argumenata: definisan je raspon dana u nedelji (1-5), što znači da se cron job neće izvršavati samo jedan dan u nedelji (1), ili svakog dana (*).

.... izvršava se u 16:31, svakog dana koji odgovara rasponu od 1 (ponedeljak), do 5 (petak).

Nabrajanje

Ukoliko se umesto jedne vrednosti, nabroje dve ili više vrednosti, u obliku v1, v2, v3 .... vn (broj vrednosti praktično je proizvoljan), cron job će biti pokrenut za svaku od nabrojanih vrednosti (umesto samo jedanput).

		
0 12 1,12,21,27 * * root /.skripte/bekap_dnevni.sh
		
	
Slika 85. - Primer nabrajanja mogućih vrednosti za jedan od argumenata: definisani su dani u mesecu (1, 12, 21. i 27) - tokom kojih se cron job može pokretati (što praktično znači da će se skripta bekap_dnevni.sh pokretati samo navedenim danima (to jest, neće se pokretati ostalim danima)).

U gornjem primeru, skripta se pokreće tačno u podne, prvog dana u mesecu, 12. dana u mesecu, kao i 21. i 27. dana u mesecu (to jest - u opštem smislu - skripta se pokreće samo navedenim danima u mesecu).

Podela intervala na korake

Bilo koji od pet pojedinačnih argumenata (koji definišu intervale), može se podeliti na celobrojne 'korake', preko sintakse: */korak.

Na primer, sledeći cron job .....

		
0/10 * * * * root /.skripte/bekap_10_min.sh
		
	
Slika 86. - Primer: cron job pokreće navedenu skriptu na svakih 10 min (sa početkom u 00:00:00).

.... pokreće se svakog dana (sa početkom u 00:00) - svakoga sata - na svakih 10 min (tj. pokreće se u sledećim trenucima: 00:00:00, 00:10:00, 00:20:00 .... 23:59:40, 23:59:50).

Kombinacije

Parametri koji se koriste za preciziranje intervala, mogu se takođe i kombinovati.

U prvom primeru ....

		
0/10 8-15 * * 1-5 root /.skripte/kombinacije.sh
		
	
Slika 87. - Primer: cron job izvršava se svakog radnog dana, u periodu od 08:00 do 15:59, na svakih 10 minuta, sa početkom u 08:00
  • skripta se izvršava (samo) radnim danima
  • prvo izvršavanje je u 08:00, a poslednje u 15:50
  • u periodu od 08:00 do 15:50 (uključujući i 15:50), skripta se izvršava na svakih 10 minuta

Sledeći primer (poslednji u članku), nešto je složeniji:

		
0/15 8-15/7 * * * root /.skripte/pocetak_i_kraj.sh
		
	
Slika 88. - Primer: cron job pokreće skriptu svakoga dana, od 08:00 do (praktično) 16:00, na svakih sedam sati, na svakih 15 minuta (praktično - na svakih 15 min, u periodu od 08:00 do 09:00 i u periodu od 15:00 do 16:00, s tim da se skripta ne pokreće u 16:00, i stoga je poslednje pokretanje u 15:45).

Skripta koja je navedena kao izvršna komanda, izvršava se "na svakih sedam sati, počevši od 08:00, zaključno sa 15:45", međutim, šta navedene vrednosti zapravo znače?

Mogući "započeti" sati, određeni su preko II kolone: 8-15/7.

Za svaki započeti sat (pri čemu su jedine moguće vrednosti 8 i 15), skripta se može izvršavati na svakih 1 min - ukoliko nije drugačije definisano.

S obzirom na raspon sati i smernicu "na svakih sedam sati", skripta bi se "mogla" izvršavati (inače), na svaki pun minut između 08:00 i 08:59 i (takođe), na svaki pun minut između 15:00 i 15:59.

Međutim, budući da je u prvoj koloni navedeno ograničenje 0/15, skripta se neće izvršavati na svaki minut između 08:00 i 08:59 i između 15:00 i 15:59, već - na svakih 15 minuta.

U praktičnom smislu, navedena skripta se izvršava: u prvih i poslednjih 1h radnog vremena - na svakih 15 min.

Konkretni trenuci u kojima se pokreće skripta su sledeći:

  • na početku radnog vremena - u 08:00, 08:15, 08:30 i 08:45
  • na kraju radnog vremena - u 15:00, 15:15, 15:30 i 15:45

Naravno, primer nije (bio) 'preterano svrsishodan' sam po sebi, ali, uspešno prikazuje da postoji mogućnost definisanja vrlo specifičnih intervala (što može dobro doći nekom drugom prilikom).

Međutim, postoje i (vrlo uobičajene) situacije, u kojima definisanje (vrlo 'uobičajenih') intervala, zapravo zahteva preduzimanje dodatnih koraka (sledi objašnjenje) ....

Ograničenja (parametri koji se ne mogu zadati direktno)

Opcije koje smo do sada prikazali deluju (zaista) sveobuhvatno, ali, postoje i intervali (u toku dana), koji se ne mogu obuhvatiti preko prethodno opisane sintakse.

Recimo, moguće je definisati cron job koji se pokreće na svakih 15 min, od 8h do 16h (s tim da se za poslednji sat piše 15) ....

		
0/15 8-15 * * * root /.skripte/bekap.sh
		
	
Slika 89. - Primer: cron job za koji se može definisati interval u toku dana (od 08:00 do 16:10).

.... ali, nije moguće (npr. korišćenjem decimalnih vrednosti ili na drugi način), definisati raspon koji ne počinje i ne završava se 'na pun sat' (recimo, raspon od 07:30 do 17:30):

		
0/15 7.5-17.5 * * * root /.skripte/bekap.sh
		
	
Slika 90. - Primer: cron job za koji se ne može definisati interval u toku dana (od 07:30 do 17:30).

Ukoliko je potrebno da izvršavanje započne (i/ili da se završi), između dva puna sata, na scenu stupa 'snalaženje' (što najčešće podrazumeva navođenje jednog ili dva 'pomoćna cron job-a' (uz osnovni)):

		
30/15 7 * * * root /.skripte/bekap.sh
0/15 8-16 * * * root /.skripte/bekap.sh
0-30/15 17 * * * root /.skripte/bekap.sh
		
	
Slika 91. - Primer definisanja složenog intervala, preko 'pomoćnih' redova u kojima su definisani intervali pre i posle punog sata.

U gornjem primeru, "srednji" cron job je "glavni", dok su prvi cron job (koji važi samo od 07:30 do 08:00), i treći (koji važi samo od 17:00 do 17:30) - "pomoćni".

Za kraj ....

Na ovom mestu, završavamo uvodni serijal posvećen GNU/Linux distribucijama i slobodnom softveru, u kome smo 'pretresli' osnovne ideje i osnovne 'tehnikalije'.

U člancima koje pripremamo, bavićemo se temama koje smo na početku najavili (instalacija i podešavanje 'minimalističke' GNU/Linux distribucije, naprednije opcije shell skripti i sl), a bavićemo se i ostalim temama koje smo 'načinjali' usput, kao i mnogim drugim temama i sadržajima koji su vezani za više nego zanimljivu tematiku FOSS softvera ....

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > GNU/Linux - 4. deo – Shell skripte i automatizacija procesa
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt