shell programiranje [880,42 kib]

68
Shell programiranje Damir Kirasić Škola otvorenog računarstva FER Zagreb

Upload: letu

Post on 28-Jan-2017

247 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Shell programiranje [880,42 KiB]

Shellprogramiranje

Damir KirasićŠkola otvorenog računarstva

FER Zagreb

Page 2: Shell programiranje [880,42 KiB]

ImenovanjeDijeli pod istim uvjetima 2.5 Hrvatska

Page 3: Shell programiranje [880,42 KiB]

Shell programiranjeUNIX i LINUX shell programi su učinkovito sredstvo za rješavanje problema s kojima se sreću UNIX i LINUX programeri i administratori sustava. Osnovne principe shell programiranja bi trebali znati i «obični» korisnici za podešavanje vlastitog okruženja kao i za rješavanje nekih jednostavnijih, ponavljajučih poslova.

Namjena i svrhaOva skripta je prvenstveno namijenjena polaznicima tečaja Škole otvorenog računarstva "Shell programiranje", ali može poslužiti i kao samostalna literatura. Nakon tečaja polaznici će biti osposobljeni za pisanje shell programa. Iako se tečaj prvenstveno bavi Korn shell-om, znanje stečeno na tečaju je primjenjivo i na ostale shell-ove koje možete sresti na UNIX-u i LINUX-u.

PreduvjetiPreduvjeti za ovaj tečaj su poznavanje osnovnih UNIX (LINUX) naredbi kao što su ls, cp, cat, grep, wc, ... Također je potrebno predznanje o nekom od tekst editora kojim će se pisati programi.

TrajanjeZa osnovni tečaj shell programiranja je predviđeno 20 školskih sati. Osim osnovnog tečaja, ovaj tekst donosi i neka poglavlja i vježbe koja bi mogli svrstati u naprednije programiranje. Ako se obuhvate naprednija poglavlja i vježbe, onda je za tečaj potrebno najmanje 25 školskih sati.

NapomeneNa tečaju "Shell programiranje" obrađuje se sadržaj ove skripte, ali tečaj sačinjava i 40-tak gotovih primjera (koji nisu u ovoj skripti). Primjeri su napisani za Korn shell, ali mogu poslužiti za razumijevanje i drugih shell-ova koje srećemo na UNIX-u (LINUX-u).

Vrlo je važno da polaznici tečaja naprave i sve vježbe zadane u ovoj skripti jer se programiranje uči jedino programiranjem.

i

Page 4: Shell programiranje [880,42 KiB]

Sadržaj

1. Shell1.1 Uvod

1.2 Shell programi

1.3 Izvođenje shell programa

1.4 Temeljni programski elementi

2. Varijable i parametri2.1 Varijable i vrijednosti

2.2 Varijable okruženja

2.3 Sistemske varijable

2.4 Pozicioni parametri

3. Napredno korištenje varijabli3.1 Polja varijabli

3.2 Varijable i atributi

4. Izrazi i modifikatori4.1 Definicija i upotreba izraza

4.2 Povratni kôd i uvjetno izvođenje

4.3 Različite sintakse izraza

4.4 Tipovi izraza

4.5 Obrasci

4.6 Modifikatori

5. Kontrola tijeka i ulaz/izlaz5.1 If

5.2 While

5.3 For

ii

Page 5: Shell programiranje [880,42 KiB]

5.4 Ulaz/izlaz

5.5 Case i select

6. Aritmetika i aritmetički izrazi6.1 Cjelobrojna aritmetika

6.2 Aritmetički izrazi

6.3 Decimalna aritmetika

7. Signali i zamke7.1 Signali

7.2 Zamke

8. Funkcije8.1 Funkcije

8.2 Biblioteke funkcija

9. Važnije ugrađene naredbe9.1 Set

9.2 Shift

9.3 Eval

9.4 Exec

10. Koprocesi

iii

Page 6: Shell programiranje [880,42 KiB]
Page 7: Shell programiranje [880,42 KiB]

1 Shell

Shell je program koji se koristi za interpretiranje korisničkih naredbi i za izvođe­nje shell programa.

1.1 Uvod

UNIX i LINUX se sastoje od nekoliko glavnih komponenti:

shell

uslužni programi - aplikacije

biblioteke programa

jezgra

sustav datoteka

Shell (ljuska, ovojnica, školjka) je jedna od glavnih komponenti UNIX-a i LINUX-a. Osnovna zadaća shell-a je da interpretira naredbe koje je upisao korisnik. Može se reći da je shell program koji se koristi kao sučelje (interface) između korisnika i računala. Shell je, dakle, program koji nam na zaslon terminala prikazuje odzivni znak (npr. $) i čeka da unesemo neku UNIX naredbu. Najčešća zadaća shell-a je da pozove uslužni program kao npr. ls ili grep i da, nakon što taj uslužni program obavi svoj posao, ponovno pokaže odzivni znak.

Sklopovlje

Jezgra

Potprogrami

Aplikacija

AplikacijaShell

Slika 1.1: Glavne komponente UNIX-a

Page 8: Shell programiranje [880,42 KiB]

2 SHELL PROGRAMIRANJE

Osim jednostavnog poziva uslužnih programa, shell ima sve što je potrebno da bi se koristio kao programski jezik: varijable, if then else, funkcije itd. pa se za shell slobodno može reći da je to (interpretirani) programski jezik.

Shell je samostalni uslužni program (aplikacija) neovisan od ostalih dijelova UNIX-a. Implementiran je kao jedna jedina izvediva naredba (izvediva datoteka dobivena kompiliranjem C programa) i nije ni na koji način ugrađen u UNIX. Radi toga je na UNIX-u moguće imati istovremeno više shell-ova što se u praksi najčešće i događa. Moguće je, također, da korisnici napišu svoj vlastiti, novi shell.

Na UNIXu i LINUXu najčešći su:

Bourne shell (sh)

C shell (csh)

Korn shell (ksh)

Bourne again shell (bash)

Zsh (zsh)

Na LINUX-u je najrašireniji Bourne again shell (bash) ili neke njegove inačice. Osim gore navedenih, u praksi se pojavljuju i drugi shell-ovi: tcsh,...U gornjem popisu u zagradi su navedena imena izvedivih programa koje možemo pokrenuti i time aktivirati neki od navedenih shell-ova.

Sistem inženjer, u postupku definiranja novih korisnika, određuje uobičajeni (default) shell koji će se pokrenuti nakon prijave za rad. Za svakog korisnika se može definirati drugačiji shell – jedino je važno da je navedeni shell instaliran na sistemu.

Svaki korisnik može, nakon prijave za rad, eksplicitno pokrenuti neki od instaliranih shell-ova jednostavnim pozivom. Npr. Korn shell možemo pozvati sa ksh:

pinus% ksh$

U gornjem primjeru je početno bio aktivan csh koji je imao odzivni znak pinus% nakon čega smo eksplicitno pokrenuli novi shell pozivom naredbe ksh. Nakon aktiviranja ksh-a dobili smo novi odzivni znak $.

Početni csh je i dalje aktivan, ali on čeka da se završi onaj shell koji je pokrenut iz njega, a to je u gornjem slučaju ksh. Povratak na početni shell je s naredbom exit:

$ exitpinus%

Page 9: Shell programiranje [880,42 KiB]

SHELL 3

U daljnjim primjerima odzivni znak će se prikazivati kao $ kao da koristite ksh. Treba paziti da kada isprobavate primjere ne treba tipkati $.

Odzivni znak nije točan pokazatelj trenutno aktivnog shell-a. Najsigurniji način za utvrđivanje koji od njih je trenutno aktivan je naredba ps –f. Npr.

$ ps –fUID PID PPID C STIME TTY TIME CMD tom 5601 5596 1 10:16:53 pts/5 0:00 ksh tom 5596 5594 1 10:16:34 pts/5 0:00 -csh $

Najvažniji stupci su PID, PPID i CMD. Ime pokrenutog programa je u stupcu CMD, a jedinstveni proces-identifikator procesa (PID) je u stupcu PID. PPID je "parent PID" – identifikator procesa koji je pokrenuo proces u tom retku.

U gornjem primjeru je vidljivo da su pokrenuta dva procesa: csh sa PID-m 5596 i ksh sa PID-om 5601. Posljednji pokrenut proces, dakle trenutno aktivan shell, je ksh jer je njega pokrenuo csh što je vidljivo iz odnosa PID i PPID (parent PID).

Na nekim sistemima default shell ima u ispisu naredbe ps –f ispred sebe znak – kao oznaku za početni shell.

Razlika među pojedinim shell-ovima nisu velike. Razlikuju se sintakse pojedinih ugrađenih shell naredbi što dolazi do izražaja jedino kod programiranja. Tako će se npr. u ksh-u varijable definirati naredbom

$ x=abcda kod csh-a koristimo sintaksu

% set x=abcd

Korištenje i sintaksa osnovnih UNIX naredbi kao što su ls, cp, grep je isti i neovisan o tome koji od shell-ova koristimo.

Na tečaju koristimo ksh i slijedimo sintaksu ksh-a. bash i nešto stariji sh su vrlo slični ksh-u.

Slijedeća tablica prikazuje usporedbu različitih svojstava za najvažnije shell-ove.

sh csh ksh bash tcsh zsh rcJob control N Y Y Y Y Y NAliases N Y Y Y Y Y NShell functions Y(1) N Y Y N Y Y"Sensible" Input/Output redir. Y N Y Y N Y YDirectory stack N Y Y Y Y Y NCommand history N Y Y Y Y Y N(7)Command line editing N N Y Y Y Y N(7)Vi Command line editing N N Y Y Y(3) Y N(7)Emacs Command line editing N N Y Y Y Y N(7)Rebindable Command line editing N N N Y Y Y N(7)User name look up N Y Y Y Y Y N(7)

Page 10: Shell programiranje [880,42 KiB]

4 SHELL PROGRAMIRANJE

Login/Logout watching N N N N Y Y NFilename completion N Y(1) Y Y Y Y N(7)Username completion N Y(2) Y Y Y Y N(7)Hostname completion N Y(2) Y Y Y Y N(7)History completion N N N Y Y Y N(7)Fully programmable Completion N N N N Y Y NMh Mailbox completion N N N N(4) N(6) N(6) NCo Processes N N Y N N Y NBuiltin artithmetic evaluation N Y Y Y Y Y NCan follow symbolic links N N Y Y Y Y NPeriodic command execution N N N N Y Y NCustom Prompt (easily) N N Y Y Y Y YSun Keyboard Hack N N N N N Y NSpelling Correction N N N N Y Y NProcess Substitution N N N Y(2) N Y YUnderlying Syntax sh csh sh sh csh sh rcFreely Available N N N(5) Y Y Y YChecks Mailbox N Y Y Y Y Y N(8)Tty Sanity Checking N N N N Y Y NCan cope with large arg. lists Y N Y Y Y Y YHas non-interactive startup file N Y Y(9) Y(9) Y Y NHas non-login startup file N Y Y(9) Y Y Y NCan avoid user startup files N Y N Y N Y YCan specify startup file N N Y Y N N NNotes to the table above1. This feature was not in the orginal version, but has since become almost standard. 2. This feature is fairly new and so is often not found on many versions of the shell, it is gradually making its way into standard distribution. 3. The Vi emulation of this shell is thought by many to be incomplete. 4. This feature is not standard but unoffical patches exist to perform this. 5. A version called 'pdksh' is freely available, but does not have the full functionality of the AT&T version. 6. This can be done via the shells programmable completion mechanism.7. A library can be linked into the shell to provide this feature. 8. This can be done via the shells prompt function. 9. Only by specifing a file via the ENV environment variable.

Tablica 1.1: Usporedba shell-ova

1.2 Shell programi

Shell programi su tekst datoteke s UNIX i shell naredbama. Shell programi su ekvivalent za BAT datoteke na MS-DOSu. Na IBM hostovima se takvi programi nazivaju exec-i ili job-ovi.

Osnovna svrha shell programa je da pod jednim imenom spremimo više UNIX naredbi.

Page 11: Shell programiranje [880,42 KiB]

SHELL 5

Evo jednog jednostavnog primjera. Najprije u datoteku prvi nekim tekst editorom upišemo slijedeće retke

datewho

Nakon toga pokrenemo$ chmod a+x prvi

što će toj datoteci dati "executable" dozvolu. Zatim je moguće niz UNIX naredbi upisanih u datoteku prvi pokrenuti kao naredbu prvi:

$ prviTue Feb 18 14:37:24 MET 2003root console Feb 12 09:15 root pts/1 Feb 13 14:47 (cheetah.cc.fer.hr)db38517 pts/2 Feb 18 13:14 (gnjilux.srk.fer.hr)tb37062 pts/4 Feb 18 09:21 (gnjilux.srk.fer.hr)damir pts/6 Feb 17 13:31 (damir.cc.fer.hr)bsram pts/8 Feb 18 10:34 (pr.zemris.fer.hr)bsram pts/9 Feb 18 09:14 (pr.zemris.fer.hr)logadm pts/10 Feb 17 12:07 (damir.cc.fer.hr)tk37714 pts/11 Feb 18 14:30 (cm7.cmu.carnet.hr)$

Na zaslon ćemo dobiti izlaze iz standardnih UNIX naredbi date i who.

Ako slučajno dobijete poruku "ksh: prvi: not found", to znači da vaše tre­nutno kazalo nije u popisu kazala varijable PATH. Potrebno je napraviti: export PATH=$PATH: što će omogučiti pronalaženje naredbi u trenutnom kazalu jer PATH završava sa znakom ":".

Zašto učimo shell programiranje?Evo najprije pregleda osnovnih razloga za učenje shell programiranja, a zatim slijedi opis:

- Skraćujemo repetitivne poslove

- Sistemske i korisničke pokretačke procedure.

- Brzo i učinkovito napravimo veliki posao.

- Izrada programskih prototipova i programa omotača.

Page 12: Shell programiranje [880,42 KiB]

6 SHELL PROGRAMIRANJE

Sve sistemske pokretačke procedure, koje se aktiviraju kod podizanja UNIX-a, pisane su kao shell programi. Radi toga, svaki ozbiljniji sistem inženjer mora poznavati shell programiranje. Ovisno o tipu UNIX-a, pokretačke procedure su smještene u /etc/rc2.d i/ili u nekim drugim kazalima. Korisničke pokretačke procedure se izvode svaki puta kada se korisnik prijavi za rad. Ako je standardni shell csh, onda se koriste .login i .cshrc datoteke, a ako se koristi ksh ili sh pokretačka procedura je definirana sa .profile datotekom. Zato i “obični” korisnici trebaju znati barem najosnovnije o shell programiranju.

Shell programi nam omogućuju obavljanje velikih poslova na UNIXu vrlo učinkovito i brzo. Za takve programe bi nam trebalo puno više vremena da ih isprogramiramo u nekom od programskih jezika kao što su C++ ili Java.

Shell programi se mogu koristiti za izradu programskih prototipova. Nakon što smo provjerili program-prototip, možemo ga prepisati u neki drugi programski jezik. U praksi se događa da se takovi programski prototipovi pokažu dovoljno dobrima i da se prepisivanje u druge programske jezike potpuno ispusti.

Shell programe koristimo kao programe-omotače oko već postojećih programa. Tako npr. kratki primjer koji slijedi prikazuje kako se postojeći program za sortiranje može iskoristiti za sortiranje po bilo kojoj kodnoj stranici odnosno abecedi.

#!/bin/ksh#abeceda1=”....”abeceda2=”....”tr $abcededa1 $abeceda2 | sort | tr $abeceda2 $abeceda1

Bez ulaženja u suvišne detalje – u gornjem primjeru se najprije definiraju dvije varijable abeceda1 i abeceda2. Zatim se poziva standardna UNIX naredba tr koja svaki ulazni znak iz abecede1 pretvara na izlazu u ekvivalenti znak iz abecede2. Varijabla abeceda2 mora definirati jednak broj znakova kao i abeceda1 tako da svaki znak iz abecede1 ima svoj par u abeceda2. Također se abeceda2 mora tako napraviti da to bude niz znakova po točnom ASCII redosljedu jer se nakon toga poziva standardni UNIX sort koji sortira po ASCII znakovima. Na kraju je još samo potrebno zamijeniti sortirane retke sa prvobitnim znakovima što radi druga naredba tr sa obrnutim redosljedom varijabli. Čitav ovaj program čita podatke sa standardnog ulaza, a sortirani izlaz šalje na standarnu izlaz. Ako se ovaj shell program nazove hrsort, onda bi njegovo pokretanje moglo izgledati ovako:

$ hrsort < ulazna_datoteka > izlazna_datoteka

Shell programi imaju i nedostatke:

- relativna sporost (u odnosu na npr. C programe)

- previsoka razina naredbi

Page 13: Shell programiranje [880,42 KiB]

SHELL 7

- složena sintaksa: z=$(print scale=3;print “${x[a+1]}*3.14”|bc)

Shell programe, dakle, upisujemo nekim od editora u tekstualnu datoteku kao što bismo pisali izvorni kod za bilo koji programski jezik. Obzirom da je shell interpreter, nije potrebno (niti je moguće) kompilirati shell programe.

1.3 Izvođenje shell programa

Izvođenje shell programa je moguće na 4 načina:

1. ksh prog.ksh,2. . prog.ksh,3. chmod a+x prog.ksh; prog.ksh,4. exec prog.ksh

Najčešće se koristi 3. način. Uočite da je prije pokretanja samog programa, u ovom slučaju se datoteka zove prog.ksh, potrebno dodati execute dozvolu na toj datoteci.

U prvom načinu se najprije eksplicitno poziva sam shell (u gornjem primjeru je to ksh), kojem se kao argument prosljeđuje ime datoteke s programom.

U drugom slučaju se koristi posebna ugrađena naredba . (točka) iza koje slijedi ime datoteke s programom. Za razliku od prvog načina, ovaj način se koristi kada shell program želimo pokrenuti s istim okruženjem (environment) i u istom procesu koji se koristi u trenutno aktivnom shell-u a iz kojeg pokrećemo shell program. U prvom načinu izvođenja se stvara potpuno nov proces i okruženje za izvođenje shell programa. O okruženju shell-a će biti više riječi kasnije.

!!! Za csh se umijesto točke koristi naredba source.

Četvrti način izvođenja se razlikuje od ostalih po tome što se trenutno aktivni shell potpuno zamijenjuje shell programom – završetkom tog novog shell programa izvesti će se logout.

Na UNIX-u je obično instalirano više shell-ova pa bi moglo doći do zbrke oko toga koji će shell interpretirati shell program kojeg želimo pokrenuti. Da bi se izbjegla zbrka na početku shell programa moguće je eksplicitno definirati ime interpretra kojeg želimo koristiti:

#! /usr/bin/ksh

Page 14: Shell programiranje [880,42 KiB]

8 SHELL PROGRAMIRANJE

Na ovaj način moguće je definirati i programe za neki drugi interpreter kao što je perl ili tcl. U tom slučaju moramo navesti puno ime interpretera za koji želimo da interpretira ostatak datoteke: npr. #! /usr/local/bin/perl ili #! /bin/nawk.

1.4 Temeljni programski elementi

Slijedeći primjer će prikazati temeljne programske elemente kao što su parametri, varijable, izrazi i kontrola tijeka.

Program će se koristiti kao jednostavno pomagalo za pregled našeg osobnog telefonskog imenika. Podaci o imenima osoba, telefonski brojevi i odjelima zapisani su u tektualnu datoteku s koju smo nazvali "imenik". Ta bi datoteka mogla izgledati ovako:

Ana 123 CIPDavor 421 VNEMario 117 APRTomislav 133 CIP. . .

Naš shell program koji će pretraživati gornju datoteku će se zvati tel, a njegova upotreba bi mogla izgledati ovako:

$ tel anaAna 123 CIP$

U slučaju da se kod pokretanja ne navede niti jedno ime (parametar), ispisati će se cijela datoteka "imenik". Ako korisnik navede više imena, za svako ime će se napraviti pretraga u imeniku, a ako se navede ime koje ne postoji u imeniku neće se ispisati ništa. Program će raditi i ako navedemo ime odjela. Npr. za

$ tel CIPAna 123 CIPTomislav 133 CIP$

Ovako bi mogao izgledati program tel.

Page 15: Shell programiranje [880,42 KiB]

SHELL 9

Primjer 1.1: Pretraga telefonskog imenika

Retci programa su označeni brojevima koji nisu sastavni dio programa). Program započinje sa eksplicitnom definicijom interpretera (shell-a) koji želimo da se pokrene i da interpretira retke ovog programa.

U drugom retku je definirana varijabla imenik čija je vrijednost ime datoteke koja će se pretraživati. Iako to nije nužno za ovaj program, dobro je da se takve stvari definiraju na jednom mjestu, tako da se eventualna promjena imena te datoteke može napraviti samo na jednom mjestu.

Retci 3-6 su jedna if naredba za kontrolu tijeka kojom ispitujemo da li je broj navedenih imena, odnosno broj ulaznih parametara, jednak 0. To ispitivanja se obavlja s aritmetičkim izrazom (( $# == 0 )). Ako je broj ulaznih parametara 0, prikazuje se sadržaj datoteke definirane varijablom imenik pomoću naredbe more.

U reku 7 započinje for petlja kojom ćemo za svako navedeno ime pokrenuti naredbu grep koja će pretražiti imenik. Koristimo –i opciju koja znači da se ignoriraju razlike između velikih i malih slova. Naredba for se izvodi tako da vrijednost varijable navedene iza for ("ime") poprima redom sve vrijednosti parametara navedenih kod poziva programa tel. Obratite pažnju da će se, ako nije naveden ni jedan parametar, preskočiti izvođenje naredbe for. je je popis parametara prazan.

Program završava pozivom naredbe exit.

Svi programski elementi koji su ovdje samo kratko spomenuti biti će detaljnije obrađeni u slijedećim poglavljima.

1 #! /usr/bin/ksh –p2 imenik="imenik"3 if (( $# == 0 ))4 then5 more $imenik6 fi7 for ime8 do9 grep –i $ime $imenik10 done11 exit 0

Page 16: Shell programiranje [880,42 KiB]

10 SHELL PROGRAMIRANJE

Vježbe:

1.1 Napišite shell program tko koji na zaslon prikazuje prvo izlaz iz naredbe finger, a zatim trenutni datum i sat.

1.2 Napišite shell program aktivni koji na zaslon prikazuje broj trenutno aktivnih korisnika (pomoć: pokušajte spojiti naredbe who i wc).

Page 17: Shell programiranje [880,42 KiB]

2 Varijable i parametri

2.1 Varijable i vrijednosti

Varijable su osnovno programersko pomagalo. Varijable možemo definirati kao vrijednosti koje imaju ime. Treba, dakle, razlikovati ime varijable i vrijednost varijable. Imena varijabli gradimo iz slijedeće abecede: a-z A-Z 0-9 .-_. Ime varijable ne smije započinjati sa brojkom (dok npr. ime datoteke možemo započeti brojkom).

Primjeri za definiranje varijabli:x=abcdey=”abc def”

U gornjim primjerima smo definirali dvije varijable x i y kao i njihove vrijednosti. Ono što je u gornjim primjerima s desne strane jednakosti su znakovne konstante.

!!! S lijeve i desne strane jednakosti ne smije biti razmak.

Vrijednost varijable dobivamo sa $x. Moguća je i sintaksa ${x}. Vrijednost varijable se na zaslon može prikazati naredbom print ili echo:

print $xabcde

Ako želimi definirati varijablu, ali joj još ne želimo pridružiti nikakvu vrijednost, možemo koristiti naredbu typeset:

typeset var1

Vrijednost varijable možemo definirati na više načina. U nastavku ovog odjeljka će se prikazati više različitih načina za definiranje vrijednosti varijable.

U gornjim primjerima s desne strane jednakosti je bila znakovna konstanta. Umjesto znakovnih konstanti s desne strane jednakosti može se pojaviti i nešto drugo:

x=$yx=${y}abc

U gornjem promjeru smo u prvom retku varijabli x pridjelili vrijednost varijable y, a zatim, u drugom retku smo varijabli x pridjelili vrijednost varijable y i niz abc koji će se priljepiti na kraj vrijednosti varijable y.

Uočite da sax=y

Page 18: Shell programiranje [880,42 KiB]

12 SHELL PROGRAMIRANJE

varijabli x pridjeljujemo kao vrijednost znak y, a ne vrijednost varijable y.

Vrijednost varijable var, dakle, dobivamo sa $var ili ${var}.

Supstitucija naredbiAko želimo izlaz iz neke UNIX naredbe spremiti kao vrijednost varijable, koristimo sintaksu:

x=`date`

ili za ksh:

x=$(date)

Ovakvo izvođenje UNIX naredbi koristimo kada je potrebno izlaz iz naredbe spremiti u varijablu ili poslati na zaslon. Taj mehanizam se zove supstitucija naredbi (eng. command supstitution). To je vrlo moćno oruđe koje se može fleksibilno koristiti. Za njega postoje dvije sintakse koje su i prikazane u gornjim primjerima. Sintaksa s obrnutim jednostrukim navodnikom "`" se koristi u Bourne shell-u. Ksh prepoznaje tu staru sintaksu ali podržava i novu $(…) sintaksu. Nova sintaksa dozvoljava i ugnježđivanje: $(… $(…) ).

Read naredbaKod definiranja vrijednosti varijable moguće je neki proizvoljni redak utipkan sa tastature spremiti kao vrijednost varijable:

read x

Kada shell program naiđe na naredbu read izvođenje će se zaustaviti i program će čekati dok ne utipkamo nešto na tastaturi što će se spremiti u varijablu x. Moguće je koristiti read naredbu bez varijable:

…read…

U tom slučaju se vrijednost utipkana na tastaturi sprema u uobičajenu varijablu REPLY.

Sadržaj datotekeSlijedeći načina za definiranje vrijednosti varijable koristimo kada želimo sadržaj čitave datoteke spremiti u varijablu:

Page 19: Shell programiranje [880,42 KiB]

VARIJABLE I PARAMETRI 13

x=$(< file)

TipoviGotovo svi programski jezici razlikuju različite tipove varijabli. Ksh razlikuje dva tipa varijabli: znakovne (string) varijable koje smo do sada koristili i cjelobrojne varijable. Npr. slijedeća naredba definira varijablu var1 kao cjelobrojnu varijablu i pridjeljuje joj vrijednost 5.

integer var1=5

Nakon što smo neku varijablu definirali kao integer, u nju više ne možemo spremati običan tekst.

U varijablu možemo spremiti i vrijednost nekog aritmetičkog izraza. Aritmetika sa cjelobrojnim varijablama se koristi unutar dvostrukih zagrada. Npr. izraz:

x=$(( var + 1 ))

će varijabli x pridružiti vrijednost varijable var uvećane za 1. Detaljno o aritmetici će biti riječi kasnije.

Za prikaz varijabli i nekog teksta koristimo naredbe: print ili echo:

print 1234 $x1234 abcde

!!! Vrijednost varijable dobivamo sa $var (a ne samo var).

Brisanje varijabliBrisanje varijable se može napraviti naredbom unset:

unset x

Nakon gornje naredbe varijabla x više neće biti definirana. Još jednom se napominje da se ksh ne buni kada pokušamo prikazati nedefiniranu varijablu – shell jednostavno kao vrijednost te varijable daje prazan niz.

Slijedeći primjer prikazuje korištenje varijabli. Redak ili dio retka koji započinje sa # je komentarski dio.

Page 20: Shell programiranje [880,42 KiB]

14 SHELL PROGRAMIRANJE

Primjer 2.1: Upotreba varijabli

#! /usr/bin/ksh# var.ksh# Ilustrira: Koristenje varijabli.

# Pridruzivanje vrijednosti:var1=abcdvar1="unix \232kola" # oktalni zapis znakovavar2=$var1 # vrijednost druge varijablevar2="$var1" # vrijednost druge varijablevar2=${var1} # druga sintaksavar3=abc${var2}xyz # varijabla i dodatni tekst

# Dohvacanje i ispis varijabli:print $var1 ${var3}print "var1="$var1print "var3="${var1}" dodatni tekst"echo $var1 $var3

# Cesta greska - ispusten '$':print var1

# Varijabli var2 pridruzi izlaz iz naredbe 'date':var2=$(date)var2=`date`print $var2

# Interakcija s korisnikom:print -n "Unesite jedan redak: "read var3print "U var3 varijablu je spremljeno: $var3"

# Sadrzaj datoteke spremamo u varijablu:var3=$(< /etc/group)

# metaznak \ ili ' iskljucuje ime kao varijablu:print \$var1print '$var1'

Page 21: Shell programiranje [880,42 KiB]

VARIJABLE I PARAMETRI 15

Vježbe:2.1 Modificirajte program aktivni iz prethodnog poglavlja tako da na

zaslon dobijete:“Trenutno je prijavljeno X korisnika”.

gdje će X biti broj trenutno prijavljenih UNIX korisnika.

2.2 Varijable okruženja

Neke od varijable, bilo da ih je napravio UNIX bilo da smo ih napravili sami, mogu se definirati kao varijable okruženja (eng. environment variables). Varijable okruženja se automatski prenose u svaki pokrenuti program, dok se "obične" varijable ne prenose u pokrenute programe.

Prikaz environment varijabli i njihovih vrijednosti možemo dobiti naredbama export ili env. Npr. u mom okruženju dobivam:

$ env_=/usr/bin/envMANPATH=/usr/share/man:/opt/local/man:/usr/openwin/manSSH_TTY=/dev/pts/4PATH=/home/damir/bin:/home/damir/j2sdk1.4.1_01/bin:/usr/bin:/usr/sbin:/opt/local/bin:/usr/local/sbin:/usr/local/bin:/usr/openwin/bin:/usr/ccs/bin:CLASSPATH=.:/home/damir/j2sdk1.4.1_01/jre/lib/rt.jarLOGNAME=damirMAIL=/var/mail//damirUSER=damirSHELL=/usr/bin/kshHOME=/home/damirSSH_CLIENT=161.53.72.31 3337 22LD_LIBRARY_PATH=/usr/local/libTERM=vt100PWD=/home/damirTZ=MET. . .Kod definiranja varijabli možemo ih odmah definirati kao varijable okruženja:

export z=”abc”Važi i sintaksa:

typeset –x z=abc

Page 22: Shell programiranje [880,42 KiB]

16 SHELL PROGRAMIRANJE

Već definiranu varijablu z možemo naknadno proglasiti varijablom okruženja sa: export z ili typeset –x z.

Naredba typeset postavlja, u stvari, poseban atribut za neku varijablu. Osim export atributa mogući su i neki drugi atributi o čemu će biti riječ kasnije.

Za ilustraciju varijabli okruženja pogledajmo jedan kratak primjer koji pojašnja­va "prenošenje varijabli u drugi program" – kako je spomenuto u definiciji varijabli okruženja.

$ x=abcd varijabla je definirana u početnom shell-u

$ ksh pokrenuli smo novi shell

$ print $x$ varijabla x nije poznata u novom shell-u

Sada pogledajmo isti primjer za exportiranu varijablu:$ export x=abcd$ ksh pokrenuli smo novi shell

$ print $xabcd$ varijabla x postaje poznata u novom shell-u

Ista logika važi i za ostale programe. Bilo koji program da pokrenemo iz aktivnog shell-a, on će dobiti na raspolaganje sve varijable okruženja. Ovo je naročito važno za shell programe.

Vježbe:

2.2 Napišite kratki shell program prog1 koji će na zaslon prikazivati vrijednosti nekoliko varijabli. Prije nego što pokrenete taj program definirajte nekoliko varijabli u trenutnom shell-u i to tako da su neke definirane kao varijable okruženja.

2.3 Sistemske varijable

Osim varijabli koje sami definiramo, UNIX sam definira neke svoje varijable koje možemo gledati i po potrebi mijenjati. Te varijable koje je UNIX sam definirao nazivamo sistemske varijable.

Page 23: Shell programiranje [880,42 KiB]

VARIJABLE I PARAMETRI 17

Popis varijabli i njihove vrijednosti, bez obzira da li smo ih definirali mi ili UNIX, možemo dobiti s naredbom set. Na različitim UNIX-ima različiti korisnici će dobiti drugačije varijable i vrijednosti. Popis varijabli ovisi i o shell-u kojeg koristite. Djelomičan popis varijabli na mom UNIX-u:$ setCLASSPATH=.:/home/damir/j2sdk1.4.1_01/jre/lib/rt.jarDEF_UMASK=''ERRNO=2FCEDIT=/bin/edHOME=/home/damirIFS=' 'LD_LIBRARY_PATH=/usr/local/libLOGNAME=damirMAIL=/var/mail//damirMAILCHECK=600MANPATH=/usr/share/man:/opt/local/man:/usr/openwin/manOPTIND=1PATH=/home/damir/bin:/home/damir/j2sdk1.4.1_01/bin:/usr/bin:/usr/sbin:/opt/local/bin:/usr/local/sbin:/usr/local/bin:/usr/openwin/bin:/usr/ccs/bin:PPID=14637PS1='$ 'PS2='> 'PS3='#? 'PS4='+ 'PWD=/home/damirRANDOM=22556TERM=vt100

U gornjm ispisu smo dobili puno varijabli. Neke od tih varijabli nikada ne koristimo, a neke sistemske varijable su naročito važne:

TERM - vrijednost te varijable određuje koji tip terminala imate. Ako je ta varijabla krivo postavljena, neki programi uopće neće moći normalno raditit. Npr. vi. Isprobajte.

PATH – vrijednost te varijable daje popis kazala koja će se pretraživati da bi se našle UNIX naredbe. Ako je npr. vrijednost te varijable /usr/bin:/etc/:. onda će se redom pretraživati kazala: /usr/bin, pa /etc, pa . (trenutno kazalo). Isprobajte poremetiti PATH varijablu i pozvati neke standardne UNIX naredbe.

Interesantna je i varijabla PS1. Ta varijabla definira odzivni znak shell-a. Isprobajte. Koja je razlika između PS1='$PWD> ' i PS1=”$PWD> “ ? Isprobajte

Page 24: Shell programiranje [880,42 KiB]

18 SHELL PROGRAMIRANJE

obadvije varijante i nakon toga napravite promjenu kazala npr. cd /tmp. Obja­snite razliku.

Osim gore navedenih sistemskih varijabli, koje vidimo sa set, možemo koristiti još neke sistemske varijable. Npr. trenutni proces identifikator (PID) shell programa, ili trenutno aktivnog shell-a, se sprema u sistemsku varijablu pod imenom $. Dakle, vrijednost PID-a dobivamo sa $$. Ova sistemska varijabl se često koristi kada želimo imati neki jedinstveni identifikator, a to je automatski osigurano jer je svaki PID jedinstven.

Vježbe:

2.3 Napišite shell program priv koji će otvoriti privremenu datoteku jedinstvenog imena. Datoteku treba napraviti u kazalu /tmp. Smisao ovoga je da više korisnika istovremeno može pokrenuti program priv, ali želimo postići da svaki od njih ima svoju vlastitu privremenu datoteku. Pomoć: koristite UNIX naredbu touch, a PID je jedinstven za svako pokretanje programa priv.

2.4 Napišite program conv1 za konverziju kodnih stranica koji će čitati sa stdin i slati izlaz na stdout. Ulazne znakove u CRO7 kodu: “ČčĆćĐ𩹮ž” zapisane kao “^~]}\|[{@`” odnosno oktalno: “\136\176\135\175\134 \174\133\173 \100\140” na izlazu treba pretvoriti u CP 1250: “\310\350\306\346\320\360 \212\232\216\236”. Koristite varijable i UNIX naredbu tr. Naredba tr raspoznaje posebne znakove kao što je to gore zapisano: umjesto znaka ^ treba upisati oktalni ekvivalent \136 itd.

2.4 Pozicioni parametri

Svaki UNIX program možemo pozvati s dodatnim parametrima (argumentima) koji mogu modificirati osnovno izvođenje naredbe. Npr. opcija –l je dodatni argument koji mijenja izlaz iz naredbe ls.

Kao i sve UNIX naredbe, tako i shell programi mogu dohvaćati parametre koji se koriste kod poziva samog programa. Uobičajeno je da se ti parametri nazivaju pozicioni parametri jer je važna i njihov redoslijed.

Unutar shell programa pozicione parametre dohvaćamo kao $1,$2,...Npr. ako neki shell program prog1 pozovemo s tri parametra:

prog1 abcd klm xyz

onda će unutar tog programa prvi parametar (abcd) biti dohvatljiv kao $1, drugi parametar (klm) kao $2, a treći parametar (xyz) biti dohvatljiv kao $3.

Page 25: Shell programiranje [880,42 KiB]

VARIJABLE I PARAMETRI 19

Primjer 2.2: Parametri za shell program

Osim pozicionih parametara, UNIX omogućuje korištenje i nekih drugih varijabli koje su povezane s njima:

$0 ime shell programa

$# broj pozicionih parametara

$@ svi pozicioni parametri (kao “$1” $2” “$3”)

$* svi pozicioni parametri (kao “$1 $2 $3”)

Vježbe:

2.5 Napišite shell program telv1 koji će pregledavati telefonski imenik spremljen u datoteku imenik Program treba učitati jedan parametar i za njega ispisati odgovarajući redak iz imenik. Imenik je u formatu: ime prezime tele­fonski_broj. Npr. korištenje programa bi moglo izgledati ovako:

$ telv1 anaana 123$

# Pozicioni parametri za shell program

print "Prvi parametar: " $1print "Drugi parametar: " $2print "Treci parametar: " $3

Page 26: Shell programiranje [880,42 KiB]

3 Napredno korištenje varijabli

3.1 Polja varijabli

Ksh dozvoljava definiranje polja varijabli:set –A p1 aaaa bbbb cccc ddddd

U gornjem primjeru je definirano polje pod imenom p1 i istovremeno je pridruženo nekoliko vrijednosti za prve elemenate (članove).

Elementi polja su indeksirani od indeksa 0 (nula), a najveći mogući indeks je 4095, što može varirati od UNIX-a do UNIX-a.

Ispis prvog elementa polja koji ima indeks 0 dobivamo sa slijedećom naredbom:print ${p1[0]}aaaa

Indeks se može definirati i nekim brojevnim izrazom. Npr.print ${p1[x+1]}

Može se definirati samo jedan član polja iako polje ranije nije definirano:a[3]=”abc”

Ovime je a je definirano kao polje sa samo jednim (četvrtim) definiranim članom. Ostali članovi polja su nedefinirani.

Moguće je definirati polje i "rezervirati" određeni broj članova:typeset a[200]

Ispis svih članova polja, npr. polja p1 dobivamo sa:

print ${p1[*]}

Broj definiranih članova polja dobivamo sa izrazom:${#p1[*]}

Slijedeći primjer definira dva polja: polje za boje karata i polje za karte. Zatim se na zaslon ispisuje jedna slučajno "izvučena" karta. Za generiranje slučajnih brojeva koristi se sistemska varijabla RANDOM koja kod svakog očitanja ima drugačiju vrijednost. Za sužavanje slučajnog broja koristimo modulo operaciju % koja kao rezultat mora vratiti ostatak dijeljenja – broj između 0 i maksimalnog broja.

Page 27: Shell programiranje [880,42 KiB]

NAPREDNO KORIŠTENJE VARIJABLI 21

Primjer 3.1: Polja varijabli

Vježbe:

3.1 Napišite program koji definira cjelobrojno polje arr1 s 2-3 vrijednosti. Na zaslon ispišite zbroj prvog i trećeg člana.

3.2 Varijable i atributi

Varijabla može biti definirana kao "read-only" varijabla:typeset –r var1=abcd

To su varijable kojima vrijednost možemo pridjeliti samo jednom. Gotovo svi programski jezici imaju takav tip varijabli u C++ one se nazivaju const, u Javi final. To su, u stvari, konstante s imenom.

Ako takvoj varijabli ponovo pokušamo pridjeliti vrijednost, dobivamo poruku o grešci:

$ typeset -r var1=abcd$ var1=xyzksh: var1: is read only$ echo $var1abcd$

Naredba typeset se koristi za postavljanje raznih atributa na varijablama. Npr. sa

#! /usr/bin/ksh

set –A boja pik karo herc trefset –A karta 2 3 4 5 6 7 8 9 10 decko dama kralj asinteger x1=$((RANDOM % 4))integer x2=$((RANDOM % 13))

print ${boja[x1]} ${karta[x2]}

Page 28: Shell programiranje [880,42 KiB]

22 SHEL PROGRAMIRANJE

typeset –i8 var1=11

smo definirali cjelobrojnu varijablu var1, ali smo dodali i atribut koji označava da će se u ispisu vrijednosti te varijable na zaslonu dobivati oktalna vrijednost varijable:

print $var18#13

Općenito, sve brojevne konstante u ksh-u možemo pisati u brojevnim bazama različitim od 10. Ispred broja treba prvo napisati bazu pa znak # pa broj. Npr. za binarne brojeve: 2#1010 ili za heksadecimalne: 16#A0.

Evo još nekih važnijih atributa koje upisujemo iza typeset naredbe:

Atribut ZnačenjeiB integer i brojevna baza Bu pretvori u ‘uppercase’ - velika sloval pretvori u ‘lowercase’ - mala slovaLN lijevo pomaknuto sa max. N mjestaRN desno pomaknuto sa max. N mjestaZN popuni s vodećim nulama, max. N mjestax exportiraj varijablu

Tablica 3.1: Atributi varijabli

Još neki primjeri:typeset –Z5 a=123typeset –R10 b=ivantypeset –R10 c=ivankovictypeset –R10 d=anatypeset –R10 e=anicprint “$a $b $c”print “$a $d $e”00123 ivan ivankovic00123 ana anic

U gornjim primjeru kod ispisivanja vrijednosti varijable je jako važno da se koriste navodnici, bez navodnika neće dobro raditi.

Page 29: Shell programiranje [880,42 KiB]

NAPREDNO KORIŠTENJE VARIJABLI 23

Atributi L i R sa maksimalnim brojem znakova se koriste za ispise izvještaja kada želimo ispravno formirane stupce. Ako broj znakova u vrijednosti varijable mani od maksimalnog broja znakova, onda se preostali znakovi popunjavaju s prazninama.

Page 30: Shell programiranje [880,42 KiB]

4 Izrazi, obrasci i modifikatori

4.1 Definicija i upotreba izraza

Izrazi (eng. expressions) su programski elementi kojima definiramo logičke ili brojevne vrijednosti. Vrijednost logičkih izraza može biti true ili false, a brojevne vrijednosti mogu poprimiti cjelobrojne veličine.

Logičke izraze najčešće srećemo nakon naredbi kontrole tijeka kao što su npr. if ili while. Npr. iza if imamo logički izraz:

if logički_izrazthen . . .done

Izvođenje bilo koje UNIX naredbe ili nekog shell programa također se smatra logičkim izrazom. U slučaju da se neka naredba promatra kao izraz, vrijednost izraza je definiran povratnim kodom te naredbe.

Brojevne izraze najčešće susrećemo u indeksima polja ili kod aritmetike i aritmetičkih izraza o čemu će biti riječi kasnije.

4.2 Povratni kôd i uvjetno izvođenje

Povratni kod naredbe je broj koji UNIX postavlja nakon svakog izvođenja neke naredbe. Povratni kod zadnje naredbe automatski se sprema u sistemsku varijablu $?.

Pogledajte sa man npr. povratne kodove za naredbu grep. U man stranicama povratni kod se objašnjava u odjelku "Exit status". U slučaju da je grep našao traženi obrazac, povratni kod se postavlja u 0. Ako grep nije našao obrazac, povratni kod je 1, a ako je grep detektirao neku grešku onda se povratni kod postavlja u 2. Greška kod grep-a može nastati kada npr. tražimo neki obrazac u datoteci, a datoteka ne postoji.

Uobičajeno je u UNIX-u i LINUX-u da ispravno izvođenje naredbi, pa tako i shell programa, kao povratni kôd daje vrijednost 0. UNIX programerima se preporučuje da se drže tog pravila jer se time omogućuje jednostavnije i uniformno povezivanje nezavisno napisanih programa. Svaka UNIX naredba u man stranicama specificira koji su mogući povratni kodovi i što oni znače.

Povratni kôd naredbi omogućuje novi način izvođenja - uvjetno izvođenje:comm1 && comm2

Page 31: Shell programiranje [880,42 KiB]

IZRAZI, OBRASCI I MODIFIKATORI 25

Koristimo operator && koji se stavlja između dvije naredbe. Gornji izraz definira slijedeći način izvođenja:

najprije se izvede UNIX naredba comm1 ako ta naredba kao povratni kod vrati 0 onda se izvodi i naredba comm2 ako comm1 ne vrati 0 onda se naredba comm2 ne izvodi.

Ovakvo uvjetno izvođenje je u biti skraćeni zapis za if naredbu:

if comm1then

comm2fi

Ako nam je u shell progamu potrebna obrnuta logika, možemo koristiti || operator:

comm1 || comm2

Izvede se comm1. Ako je comm1 vratio povratni kod različit od nule, izvodi se i naredba comm2.

Evo nekoliko konkretnih primjera:rm –f f1 && print "f1 removed"who | grep joe || print "joe loged off"

Iz shell programa možemo izaći s narebom exit. Ako želimo iz shell programa postaviti povratni kod, možemo koristiti exit N gdje će N biti željeni povratni kod. Npr. exit 0 će završiti izvođenje shell programa i postaviti povratni kod u 0. Na ovaj način slijedimo konvenciju koja vrijedi za sve UNIX naredbe.

4.3 Različite sintakse izrazaIzrazi se mogu zapisati različitim sintaksama. U slijedećem odjeljku će se prikazati 5 različitih sintaksi za logičke izraze:

1) naredba npr. grep $1 imenik (exit status 0 = true)

2) test npr. test $# -eq 03) unutar [ npr. [ $var1 = “abc” ]4) unutar [[ npr. [[ $var1 = *.c ]]5) unutar (( npr. (( x < 10 ))

Page 32: Shell programiranje [880,42 KiB]

26 SHELL PROGRAMIRANJE

1) UNIX naredba (navedena pod točkom 1) nije izraz u smislu ranije definicije, ali logika je slijedeća: izvede se UNIX naredba i pogleda njezin povratni kôd. Ako je on 0 onda se "izraz" smatra istinitim.

2) Standardna naredba test koristi se za ispitivanje raznih uvjeta. Sintaksa te naredbe je prilagođena upravo ispitivanju uvjeta. U gornjem primjeru "test $# -eq 0" će vratiti 0 (dakle izraz je isitinit) ako je broj pozicionih parametara ($#) jednak (–eq) 0. U praksi se ova naredba susreće jedino u starim skriptama koje moraju biti kompatibilne s Bourne shell-om. Korisnici ksh-a koriste ugrađeno testiranje koje dobivamo uglatim ili okruglim zagradama (i zato se ovdje naredba test neće detalno obrađivati).. Korištenjem ugrađenog testiranja ujedno izbjegavamo pokretanje novog procesa kojeg ne možemo izbjeći u slučaju naredbe test.

3) Jednostruke uglate zagrade se koriste i u Bourne shell-u i u Korn shell-u. Najčešće se koriste za ispitivanje da li je varijabla jednaka nekoj vrijednosti ili slično. U gornjem primjeru ispitujema da li je vrijednost varijable var1 jednaka "abc". Za detaljniji pregled mogućeg sadržaj unutar zagrada pogledajte slijedeći odjeljak

4) Unutar dvostrukih uglatih zagrada [[ ... ]] možemo ispitivati da li je vrijednost neke varijable jednaka nekom obrascu, što nije moguće s jednostrukim uglatim zagradama. U gornjem primjeru [[ $var1 = *.c ]] je izraz kojim ispitujemo da li je vrijednost varijable var1 završava na ".c". Ukratko, dvostruke uglare zagrade daju više mogućnosti nego jednostruke – ali se mogu koristiti jedino unutar ksh-a. Za detaljniji pregled mogućeg sadržaj unutar zagrada pogledajte slijedeći odjeljak.

5. Dvostruke okrugle zagrade (( … )) koristimo za aritmetičke izraze i za samu aritmetiku. Npr. izraz (( x < 10 )) radio ono što i očekujemo, ispituje da li je vrijednost varijable x manja od 10.Unutar [[ … ]] i (( ... )) možemo koristiti && i || za kompoziciju više jednostavnih izraza.

Kada koristiti koji tip izraza?

Najbolje za ksh je [[ ... ]] ako koristimo uspoređivanje varijabli, a (( ... )) za aritmetiku i aritmetičke izraze. (U sistemskim pokretačkim procedurama koje su pisane za sh sintaksu srećemo jedino [ ... ]).

Često možemo jednu te istu stvar ispitati na više različitih načina:if [ $# -eq 0 ]; then …if [ $# = 0 ]; then …if [[ $# = 0 ]]; then …if (( $# == 0 )); then …

Page 33: Shell programiranje [880,42 KiB]

IZRAZI, OBRASCI I MODIFIKATORI 27

Nije toliko važno koji način koristimo već da smo konzistentni i da slijedimo uvijek istu sintaksu.

Vježbe:

4.1 Napišite shell program brisi koji će obrisati rekurzivno sve što je ispod kazala /tmp/priv. Prije nego što se obavi brisanje, program nas mora pitati da li stvarno želimo sve obrisati. Kao pozitivan odgovor uvažite "d", dok su svi ostali odgovori smatraju negativnim.

4.4 Tipovi izraza

Logičke izraze možemo podijeliti prema različitim kriterijima. Izraze možemo npr. podijeliti na jednostavne i složene. Složene izraze gradimo od jednostavnih pomoću operatora: &&, ||, !, i () unutar dvostrukih zagrada. && operator koristimo za logičku AND operaciju, || za logičku OR operaciju. Okrugle zagrade koristimo za grupiranje izraza, a uskličnik za negaciju.

Izraze možemo podjeliti i prema području uporabe:

1. Uspoređivanje nizova

2. Aritmetički izrazi

3. Uspoređivanje svojstava datoteka

Slijedi pregled najvažnijih tipova izraza prema gornjoj podjeli, a koje koristimo unutar zagrada: [ … ], [[ … ]] i (( … )).

1) Za uspoređivanje nizova (stringova):

string = string; string != string (umjesto "string" može naravno $var)

string = pattern; string != pattern samo unutar [[ ]]Npr.

[ $var1 = “abc” ][[ $var1 = *.c ]]

2) Za uspoređivanje brojeva i brojevnih izraza koristimo binarne operatore koji s lijeve i desne strane mogu imati broj ili u najopćentijem slučaju kompletan izraz.

exp1 –eq exp2 da li je exp1 jednako exp2exp1 –ne exp2 da li je exp1 različito od exp2

Page 34: Shell programiranje [880,42 KiB]

28 SHELL PROGRAMIRANJE

exp1 –gt exp2 da li je exp1 veći od exp2exp1 –ge exp2 da li je exp1 veći ili jednako exp2exp1 –lt exp2 da li je exp1 manji od exp2exp1 –le exp2 da li je exp1 manji ili jednako exp2

Npr.[[ $x –gt 7 && $x –lt 70 ]]

Unutar dvostrukih okruglih zagrada možemo koristiti operatore koji su uobičajeni u programskim jezicima C/C++, Java,…. Također je dozvoljena sintaksa u kojoj ne koristimo $var nego samo var za vrijednosti varijabli.

(( x == y )) da li je x jednako y(( x >= y )) da li je x veće ili jednako y. . .

Npr.(( x > 7 && x < 70 ))

Slijedi manji, kompletan primjer:

Primjer 4.1: Upotreba izraza

3) Za pronalaženje raznih svojstava datoteka kao i za uspoređivanje datoteka koristimo niz binarnih i unarnih operatora. Evo jednog primjera

if [[ $# = 2 && $1 = -f && -r $2 ]]then

#!/bin/ksh -p## uglate.ksh

if [[ $1 -gt 70 ]]then print "umirovljenik."elif [[ $1 -gt 7 ]]then print "Odrasli - Morate platiti kartu".else print "Dijete."fi

Page 35: Shell programiranje [880,42 KiB]

IZRAZI, OBRASCI I MODIFIKATORI 29

print "We have –f option and file that exists and is readable"fi

Obratite pažnju na "-r $2" – to je izraz kojim ispitujemo da li je u $2 spremljeno ime datoteke koja postoji i koja je čitljiva. Slijedi kratki opis još nekih važnijih operatora za ispitivanje datoteka:

-d file istinito ako je file kazalo

-r file istinito ako datoteka postoji i čitljiva je

-w file istinito ako datoteka postoji i može se u nju pisati

-x file istinito ako datoteka postoji i izvediva je

-s file istinito ako datoteka postoji i ima veličinu veću od 0

. . .

Binarni operatori se koriste za uspoređivanje dvije datoteke:

file1 –nt file2 file1 noviji od file2

f1 –ot f2 file1 stariji od file2

Vježbe

4.2 Modificirajte program telv1 i napišite telv2 tako da se dozvoljava da korisnik ne upiše parametar kojim definiramo ime. U tom slučaju na zaslon treba prikazati sadržaj čitave datoteke imenik.

4.5 Obrasci

Prilikom uspoređivanja nizova, ili kod drugih poslova, često se upotrebljavaju obrasci (eng. patterns). Obrascima, u stvari, iz svih mogućih nizova znakova odabiremo samo neke. Obrasci su skraćeni zapis za odabir nekih nizova. Slijedi sintaksa za najvažnije obrasce.

[abcd] bilo koji (jedan) od navedenih znakova

? bilo koji znak

* nula ili više pojava bilo kojih znakova

?(patt1|patt2|...) nula ili jedan od obrazaca unutar ( )

*(patt1|patt2|...) nula ili više obrazaca unutar ( )

Page 36: Shell programiranje [880,42 KiB]

30 SHELL PROGRAMIRANJE

+(patt1|patt2|...) jedan od obrazaca unutar ( )

!(patt1|patt2|...) svi osim bilo kojeg obrasca unutar ( )

Evo nekoliko primjera za upotrebu obrazaca:

prog[123] odabire riječi prog1, prog2 i prog3

pogl? odabire pogl1 pogl2, ali ne odabire pogl11

x*y odabire riječi koje počinju sa x i završavaju s y

para?([345]|99)1 odabire para1, para31, para991

U praksi Vam npr. može zatrebati da iz jednog kazala obrišete sve datoteke osim datoteke s izvornim kodom. Ako bi sve datoteke s izvornim kodom završavala sa ".chill", onda bi to brisanje mogli obaviti sa rm !(*.chill)

!!! Oprez kod isprobavanja naredbe rm *.

Vježbe:

4.3 Modificirajte program brisi tako da koristite obrasce i dozvolite "d" i "D". Pokušajte to još proširiti sa "da" i "DA".

4.6 Modifikatori

Modifikatori su izrazi kojima dobivamo sadržaj povezan s varijablom. Modifikatore koristimo za dobivanje default vrijednosti, za dobivanje dijelova varijabli ili za neke druge informacije vezane za varijable.

Primjeri za modifikatore:

${1-root} vrijednost $1 ili "root" ako $1 nije definiran;

može i npr. ${d-$(date)}${1=root} vrijednost $1 ili ‘root’ ako $1 nije definiran a $1 postaje root${1?poruka) vrijednost $1 ili ‘poruka’ na stderr ako nije definiran

${var1-abcd} može i bilo koja varijabla, ne samo pozicioni parametri

Modifikatori: #, ##, %, %% brišu dio varijable i kao rezultat vraćaju ono što ostaje nakon brisanja. Dio koji želimo obrisati definiramo sa obrascem, a

Page 37: Shell programiranje [880,42 KiB]

IZRAZI, OBRASCI I MODIFIKATORI 31

moguće je brisati s lijeve ili desne strane varijable. Također je moguće definirati da li se briše najmanji dio koji je definiran sa obrascem ili pak najveći mogući dio koji zadovoljava obrazac.

Uzmimo kao primjer slijedeći niz naredbi koje pojašnjavaju što znači "najmanji dio" i "najveći mogući dio" u prethodnoj rečenici.

x=/jedan/dva/triprint ${x##*/}triprint ${x#*/} jedan/dva/tri

Najprije je definirana varijabla x, a zatim se iz nje briše "najveći mogući dio" s lijeve strane (operator ##). Ono što brišemo je definirano obrascem "*/". Međutim, taj obrazac definira niz "/" – najmanji mogući niz koji zadovoljava obrazac "*/", ali i niz "/jedan/dva/" – najveći mogući niz. Operatorom ## definiramo najveći mogući, a sa # definiramo najmanji mogući niz za brisanje.

Pregled svih %, # modifikatora varijabli:

${parametar#pattern} obriši mali lijevi dio

${parametar##pattern} obriši veliki lijevi dio

${parametar%pattern} obriši mali desni dio

${parametar%%pattern} obriši veliki desni dio

Slijedeći primjer mvall.ksh ilustrira upotrebu modifikatora. Svrha ovog programa je da npr. promijeni imena datoteka koje završavaju sa ".C" u imena koja završavaju s ".cpp". Stari završetak datoteka (npr. ".C") i novi završetak (npr. ".cpp") su ulazni parametri za taj program. Ako bismo naredbu pokrenuli npr. sa

mvall.ksh .awk .nawk

onda bi program sve datoteke koje zvršavaju s ".awk" preimenovao tako da završavaju s "nawk".

Page 38: Shell programiranje [880,42 KiB]

32 SHELL PROGRAMIRANJE

Primjer 4.2: Upotreba modifikatora

Najvažniji dio gornjeg programa je izraz ${filename%%${1}} i upotreba modi­fikatora %% koji briše desni dio iz varijable filename i to onaj dio koji je speci­ficiran sa $1.

Vježbe:

4.4 Isprobajte slijedeći niz naredbi:x=/jedan/dva/triprint ${x##*/}print ${x%/*}print ${x#/jedan/}x=jedan/dva/triprint ${x%%/*}

U praksi se pokazuju korisni i slijedeći modifikatori:

${#parametar} dužina stringa

${#arr[*]} broj definiranih članova u polju

Slijedeći primjer ilustrira upotrebu modifikatora za dužinu niza:x=abcdefgprint ${#x}7

#! /usr/bin/ksh## Mijenja imena datoteka koje zavrsavaju na $1# u datoteke tako da zvrsavaju na $2

for filename in *${1}do mv $f ${filename%%${1}}${2}done

Page 39: Shell programiranje [880,42 KiB]

IZRAZI, OBRASCI I MODIFIKATORI 33

4.5 Početni substring od varijable možete dobiti sa ${x%???}, a krajnji dio kao ${x#???}. Broj upitnika označava broj znakova koje želimo obrisati. Probajte za x=1234567 s različitim brojem upitnika.

Page 40: Shell programiranje [880,42 KiB]

5 Kontrola tijeka i ulaz/izlaz

Ksh podržava slijedeće naredbe kojima definiramo redoslijed izvođenja:if ... then...fiwhile, untilforcaseselect

5.1 If

Sintaksa za naredbu if:

if izraz then ... [elif izraz ...then ....else...]fi

elif i else dijelovi su opcionalni – ne moraju biti prisutni. Ono što moramo imati kod korištenja je if izraz then … fi. Iza if i elif slijedi neki logički izraz. then MORA biti iza if i elif, a NE SMIJE biti iza else. Kao što je već napomenuto u uvodu, shell sintaksa nije baš najbolji primjer za jednostavnost i konzistentnost programskog jezika.

Slijedeći primjer je modifikacija već prikazanog primjera. Ovdje koristiom sve dijelove if sintakse.

Primjer 5.1: Upotreba if naredbe sa svim dijelovima

Izrazi su objašnjeni u prethodnom poglavlju.

#! /usr/bin/ksh

if (( $1 > 70 ))then

print “umirovljenik”elif (( $1 < 7 ))then

print “dijete”else

print “odrasli”fi

Page 41: Shell programiranje [880,42 KiB]

KONTROLA TIJEKA I ULAZ/IZLAZ 35

5.2 While

While je petlja koja omogućuje repetitivno izvođenje skupa naredbi. Sintaksa za while:

while izrazdo ...done

U slijedećem primjeru ispisujemo 15 redaka s rastućim brojevima:

Primjer 5.2: while petlja

U praksi se vrlo često koristi petlje kojom čitamo redak po redak iz ulazne datoteke, nešto napravima s njima i eventualno rezultat pošaljemo na zaslon:

Primjer 5.3: Obrada redak-po-redak

U primjeru 5.3 čitaju se ulazni podaci redak po redak sa standardnog ulaza jer to radi naredba read. Shell program koji bi sadržavao taj odsječak bi koristili ovako:

prog < input_file

integer x=1while (( x <= 15 ))do

print $x(( x = x + 1 ))

done

while readdo

# ovdje nešto napravi s retkom# redak je sadržan u varijabli $REPLY

print $REPLYdone

Page 42: Shell programiranje [880,42 KiB]

36 SHELL PROGRAMIRANJE

!!! Obrazac prikazan u prethodnom primjeru se vrlo često koristi u praksi.

Ako trebamo beskonačnu petlju:while truedo

… # ove naredbe se beskonačno izvodedone

Osim while koristi se i naredba:

until izrazdo... done

Izvedi naredbe dok izraz nije istina (rijetko se koristi).

Unutar petlji možemo korisiti naredbe break i continue. Naredba break uzrokuje izlaz iz while (ili neke druge) petlje dok continue uzrokuje skok na početak petlje.

Vježbe:

5.1Napišite shell program koji će čitati redak po redak sa standardnog ulaza i ispisivati te retke ispred kojih će ubaciti redni broj retka. Isprobajte za neku datoteku. Npr. za datoteku imenik: prog < imenik

5.2 Napišite shell program shead koji će kao parametar pročitati broj N. Ako nema tog parametra default vrijednost je 10. Zatim treba čitati retke sa standardnog ulaza i prikazati točno N (ili 10) početnih redaka.

5.3 For

for je vrlo korisna i močna. Nešto se razlikuje od for petlji koje nalazimo u programskim jezicima kao što su C++, C# ili Java.

Page 43: Shell programiranje [880,42 KiB]

KONTROLA TIJEKA I ULAZ/IZLAZ 37

Sintaksa za for:

for variable in word1 word2 ...do ....done

ili druga moguća sintaksa:for variable # word1 word2 ... se uzimaju iz $@do ...done

U obje sintakse varijabla definirana iza for poprima redom vrijednosti iz liste riječi. U prvoj sintaksi lista riječi je eksplicitno navedena iza ključne riječi in. U drugoj sintaksi nemamo niti listu riječi niti ključnu riječ in – lista se automatski uzima iz liste pozicionih parametara: $1, $2, $3, …U prvoj sintaksi listu riječi word1 word2 ... najčešće ne upisujemo eksplicitno nego ju dobivamo sa npr. obrascem *.c ili sa supstitucijom naredbi $(....). Upravo u tome leži snaga for petlje. Lista riječi se može dobiti na vrlo različite načine.

Primjer:for var1 in *.kshdo lp $var1 # ovdje nešto napravimo s datotekomdone

U gornjem primjeru varijabla var1 će redom poprimati imena datoteka iz trenutnog kazala koja završavaju na .ksh. U prvom prolazu kroz petlju vrijednost var1, dakle $var1, će biti prvo ime datoteke, u drugom prolazu drugo ime itd. sve dok se ne iscrpu sva imena.

Ako je lista iza in prazna, jer npr. nema datoteka definiranih sa obrascem, onda se petlja neće izvesti niti jednom.

Slijedeći kratki primjer ispisuje sve pozicione parametre pomoću for petlje. Koristi se druga sintaksa bez eksplicitno navedene liste riječi:

for paramdo print $paramdone

Page 44: Shell programiranje [880,42 KiB]

38 SHELL PROGRAMIRANJE

U slijedećem primjeru lista riječi se dobiva supstitucijom naredbe. Svrha programa je da svim ljudima čije su adrese upisane u datoteku popis poša­ljemo email sa sadržajem u datoteci pismo.

Primjer 5.4: For petlja i supstitucija naredbi

U gornjem primjeru će varijabla ime sadržavati redom sve riječi iz datoteke popis, a u tijelu petlje ćemo svima sa popisa poslati Email spremljen u dato­teku pismo.

Vježbe:

5.3 Modificirajte ranije napisani program telv2 u tel koji će biti konačna inačica tog programa. tel mora ispravno reagirati na više parametara, a ako parametara nema treba ispisati čitavu datoteku imenik.

+5.4 Modificirajte program conv1 u conv2 tako da možemo pretvarati više kodnih stranica, a ne samo dvije kao u conv1.

+5.5 Napišite shell program koji će preimenovati sve datoteke u trenutnom kazalu *.ksh u *.csh. Modificirajte ga tako da 2 nastavka (“ksh” i “csh”) možemo učitati kao parametre.

5.4 Ulaz i izlaz

Osim uobičajenih redirekcija za ulaz/izlaz ( >, <, >>, >|) ulaz podataka u shell programima se obavlja naredbom read, a ispis (izlaz) naredbom print ili echo.

!!! Kod $ naredba > f1 briše se sadržaj postojeće datoteke f1.

Neke važnije upotrebe i opcije naredbe read:

#! /usr/bin/ksh

for ime in $(< popis)do mailx $ime < pismodone

Page 45: Shell programiranje [880,42 KiB]

KONTROLA TIJEKA I ULAZ/IZLAZ 39

read var # čita redak iz stdin u varijabluread # bez varijable => REPLYread var1 var2 var3 # čita redak i riječi se razvrstavju u var1 var2 ...read -r var # NE interpretiraj ‘\’ kao nastavak retkaread -uN var # čitaj iz deskriptora Nread –p # čitaj iz koproces-aread var?”Unesite redak” # pošalje definirani ‘prompt’ pa čita u varNeke važnije upotrebe i opcije naredbe print:

print argument ... # ispisuje argumente na zaslon terminalaprint - argument ... # argument može početi sa ‘-‘

(probajte bez minusa: x=”-a”; print $x)print -r argument ... # ne interpretiraju se metaznakovi: \a,\t, \n, ...print -R argument ... # isto ka ‘-‘ i ‘-r’print -n argument ... # bez novog retka na krajuprint -uN argument ... # izlaz pošalji u deskriptor N

Za čitanje i pisanje iz datoteka koje nisu standardnu ulaz i standardni izlaz možemo, naravno, koristiti standardne operatore za redirekciju: <, >, >>.

Npr. za obradu redaka iz ulazne datoteke i spremanje rezultata u neku poznatu izlaznu datoteku možemo koristiti obrazac:

Primjer 5.5: while s redirekcijom

U jednom shell programu je moguće istovremeno otvoriti više datoteka naredbom exec. (Važi samo za ksh). Npr. naredbe:

exec 3< ulaz exec 4< izlaz

otvaraju datoteku s imenom ulaz i pridjeljuje joj opisnik 3 i datoteku izlaz i pridjeljuju joj opisnik 4. Opisnik 3 se koristi za čitanje iz datoteke ulaz, a opisnik 4 za pisanje u datoeku izlaz. Nakon što smo dobili opisnike datoteka, možemo ih koristiti za čitanje i pisanje. Npr. naredba

#! /usr/bin/ksh

while read –r linedo

print –r $linedone < ulazna > izlazna

Page 46: Shell programiranje [880,42 KiB]

40 SHELL PROGRAMIRANJE

read –u3 readak

će pročitati jedan redak iz opisnika 3 (datoteke ulaz) i spremiti taj redak u varijablu redak, a

print –u4 $redak

će ispisati vrijednost varijable redak u opisnik 4 (datoteka izlaz).

Pogledajte primjer u 9. poglavlju koji prikazuje kompletnu upotrebu više otvo­renih datoteka i korištenje naredbi read –u i print –u.

5.5 Case i select

Case naredba ima sličnu sintaksu jezicima C++ i Java:

case word in(patt1|patt2|...)

commands ;;(patt3|patt4)

commands ;;(*)

commands ;;esac

Slijedeći primjer prikazuje upotrebu naredbe case.

Primjer 5.6: Upotreba naredbe case

#! /usr/bin/ksh

print –n "Zelite nastaviti? "read odgovorcase $odgovor in([dD]|da|DA)

print “Odgovor potvrdan” ;;([nN]|[ne|NE)

print “Odgovor negativan” ;;(*)

print “Neodređeni odgovor” ;;esac

Page 47: Shell programiranje [880,42 KiB]

KONTROLA TIJEKA I ULAZ/IZLAZ 41

Naredba select se koristi za izgradnju programa s jednostavnim izbornicima (menu). Vrlo često se kombinira s naredbom case.

select identifier [ in word1 word2 ... ]do

commandsdone

Slijedeći primjer naredbe select će na zaslon prikazati izbornik i čekati da upišemo naš izbor nakon čega se ispisuje odgovarajuća poruka. Nakon pokretanja programa dobivamo slijedeće:

1) cow3) pig4) sheep5) quitPick an animal:

Uočite da je čitav izbornik i učitavanje odgovora napravljeno automatski, a veći dio primjera čini naredba case:

Primjer 5.7: Naredba select

#! /usr/bin/ksh## Ilustrira: select

PS3="Pick an animal: "

select animal in cow pig sheep quitdo case $animal in (cow) print "Mooooo" ;; (pig) print "Oiink" ;; (sheep) print "Baaaaa" ;; (quit) exit 0 ;; ('') print "Not in the barn" ;; esacdone

Page 48: Shell programiranje [880,42 KiB]

6 Aritmetika i aritmetički izrazi6.1 Cjelobrojna aritmetika

Cjelobrojna aritmetika se može izvoditi na dva načina. Ksh ima ugrađenu cjelobrojnu aritmetiku – mogućnost izvođenja matematičkih operacija sa cijelim brojevima. U Bourne shellu se koristi uslužni program expr koji obavlja cjelobrojnu aritmetiku jer sh nema ugrađenu aritmetiku. Radi toga u shell programima koji su pisani za sh nalazimo naredbu expr.

Naredba expr radi 10-tak puta sporije od ugrađene aritmetike, tako da ju treba koristiti jedino ako za to imamo opravdani razlog.

Evo jednostavnog primjera za naredbu expr kojim vrijednost varijable a povećavamo za 1.

a=`expr $a + 1`

Ugrađena aritmetika (prisutna samo u ksh-u) se koristi unutar dvostrukih oblih zagrada ili iza naredbe let. Sintaksa je jednaka i za zagrade i za naredbu let.

Primjeri:(( a = a + 1 ))let “a = a + 1”x=$(( z + 1 )) # supstitucija naredbi i aritmetika

Obratite pažnju da s desne strane jednakosti ne moramo ispred varijable pisati $ da bismo dobili njenu vrijednost - iako nije greška ako napišemo

(( a = $a + 1 )).

Za aritmetiku u ksh-u vaši također pravilo da brojeve možemo pisati i u brojevnim sustavima različitim od uobičajenog dekatskog sustava:

8#12 # oktalno broj 12 – dekatski = 10

2#1010 # binarno 1010 – dekatski =10

Vrijedi dakle općenito: b#broj gdje je ‘b’ baza, a ‘broj’ znamenke tog broja u bazi ‘b’.

C++ i Java programeri su već upoznati sa nekim specifičnim kombinacijama operatora koji se javljaju i u ksh:

var op expr npr. let “ i += 1 “ je isto kao let “ i = i + 1”

Page 49: Shell programiranje [880,42 KiB]

ARITMETIKA I ARITMETIČKI IZRAZI 43

6.2 Aritmetički izrazi

Aritmetičkim izrazima obično definiramo neke brojevne ili logičke izraze.Često ih srećemo kao indekse u poljima varijabli, kod ispitivanja broja pozicionih parametara i sl.

Primjeri za aritmetičke izraze:while (( i <= 10 )) ...if (( (a + 1) * 5 != -b )) ..while (( ! (x % 2 == 0) )) ...if (( godine > 30 && godine < 50 )) ...

Za složenije izraze možemo koristiti grupiranje jednostavnih izraza, negaciju i sl. Slijedeći popis daje važnije operatore i njihovu upotrebu u aritmetičkim izrazima:

Operatori za aritmetiku: + - * / %Grupiranje, predznak i negacija: (...), -expression, !expressionLogičko uspoređivanje brojeva: < <= > >=Logičko uspoređivcanje izraza: expression == expression, expr != exprSloženi izrazi: expr1 && expr2 ili expr1 || expr2

Nemojte zaboraviti da na ovaj način možemo računati jedino s cijelim brojevima. Za korištenje decimalne aritmetike moramo koristiti neku od vanjskih naredbi i supstituciju naredbi – pogledajte slijedeći odjeljak.

Vježbe:

6.1 Napišite program karta koji će na zaslon prikazati slučajnu kartu. Npr. “tref dama” ili “pik 4”. (Pomoć: upotrebite polja, varijablu RANDOM i operator ‘%’).

++6.2 Modificirajte program karta tako da se napravi kompletno dijeljenja karata za 4 igrača. Pazite da kartu koju ste već podjelili ponovo ne djelite. (Nema rezervnih asova u rukavu).

6.3 Decimalna aritmetika sa ‘bc’

Decimalnu aritmetiku (brojevi sa decimalnom točkom) moramo obavljati standardnim UNIX uslužnim programom bc.

Page 50: Shell programiranje [880,42 KiB]

44 SHELL PROGRAMIRANJE

Primjeri koje možemo isprobati i interaktivno:print “scale=3;3.14*1.3” | bcx=$(print “scale=4;3.14*1.3” | bc)y=$(print “scale=4;$x+1.3” | bc)

!!! Shell ne podržava decimalnu aritmetiku.

Page 51: Shell programiranje [880,42 KiB]

7 Signali i zamke

Signali su poruke koje jedan proces može poslati drugome. Zamka je mehanizam kojim proces prima poruke – signale i određuje daljnje izvođenje.

7.1 Signali

Signali su jednostavan mehanizam komuniciranja između neovisnih procesa.

Sa korisničke razine signale šaljemo naredbom kill. Npr. naredba:

kill –2 1234 5678

će poslati signal br. 2 procesima koji imaju identifikatore 1234 i 5678.

Signali su na UNIX-u definirani brojevima ili imenima. U naredbi kill možemo koristiti ili brojeve ili imena signala. Popis imena signala možemo dobiti naredbom kill –l. Na mom UNIX-u dobivam slijedeći popis:

$ kill -lEXIT HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM USR1 USR2 CLD PWR WINCH URG POLL STOP TSTP CONT TTIN TTOU VTALRM PROF XCPU XFSZ WAITING LWP FREEZE THAW CANCEL LOST RTMIN RTMIN+1 RTMIN+2 RTMIN+3 RTMAX-3 RTMAX-2 RTMAX-1 RTMAX

Imena signala su poredana prema brojevima signala. Tako npr. signal br. 0 ima ime EXIT, signal br. 1 HUP, a signal br. 24 TSTP.

Programima koji su se počeli izvoditi možemo poslati neke signale sa tastature, bez korištenja kill naredbe:

Tipka ^C šalje signal 2 (INT)Tipka ^\ šalje signal 3 (QUIT)Tipka ^Z šalje signal 24 (TSTP)

^Z odnosno signal 24 se koristi za privremeno zaustavljanje programa. Program se može nastaviti izvoditi u prednjem planu sa fg naredbom koja, u stvari, šalje signal 25 (CONT) zaustavljenom procesu.

Nemojte zaboraviti da se naredbom stty mogu promijeniti tipke za slanje pojedinih signala. Ako nešto ne radi kako treba, provjerite trenutno stanje sa stty –a.Signal br. 9 odnosno KILL je signal za bezuvjetno ubijanje procesa. Međutim treba imati na umu da korisnici mogu slati signale jedino svojim vlastitim procesima – procesima koje su sami stvorili. Točnije rečeno, ako korisnik pošalje neki signal (uključujući i KILL signal) nekom procesu koji ne pripada

Page 52: Shell programiranje [880,42 KiB]

46 SHELL PROGRAMIRANJE

njemu, odredišni proces će ignorirati primljeni signal. Možete zamisliti kakav bi to bio kaos da svatko može svakome slati signale i da odredišni proces ne može ignorirati primljeni signal.

U praksi se često pojavljuje potreba da ubijemo neke pokrenute programe, a ne znamo im PID-ove. Slijedeći redak može poslužiti za pronalaženje PID-a od nekog programa kojemu znamo ime. Npr. za program čije je ime 61trap.ksh$ ps -f | grep 61trap.ksh | grep -v grep | awk '{print $2}'

Ako želimo nekom programu poslati KILL signal, a ne znamo njegov PID, to bi mogli obaviti slijedećom naredbom:$ kill –9 $(ps –f|grep 61trap.ksh|grep -v grep|awk '{print $2}')

Doznavanje PID-a nekog programa i ubijanje programa za koga znamo ime su česte operacije. Te dvije operacije su implementirane standardnim UNIX naredbama pgrep(1) i pkill(1). One koriste regularne izraze i imaju više korisnih opcija.

Naredba kill može poslužiti za «raščiščavanje» zaglavljenog terminala. Jedan od mogućih načina je slijedeći:

Prijavimo se na drugom terminalu i s naredbom tty doznamo ime tog drugog terminala.

Pokrenemo naredbi who –u. Moramo vidjeti da smo dva puta prijavljeni. Pronađemo redak s prvim (zaglavljenim) loginom i očitamo zadnji broj u tom retku – to je PID od shell-a. (Zaglavljeni login će imati drugačiji tty od onog kojeg smo dobili u točki 1).

Ubijemo taj shell naredbom kill -9 PID. (Ubijanje login shell-a najčešće znači i ubijanje svih procesa koji su pokrenuti iz njega). Ako želimo ubiti samo pojedini program, najbolje je koristiti pkill.Signale možemo poslati i hvatati iz našeg vlastitog C programa. Za to koristimo pozive podprograma ili jezgrenih procedura kao što je npr. signal(3) ili kill(2).

7.2 Zamke

Prilikom pisanja shell programa možemo definirati kako će naša skripta reagirati na primljene signale. Za hvatanje signala u shell programima koristimo naredbu trap (hvatamo signale u zamku).

Slijedeći primjer prikazuje elementarnu upotrebu naredbe trap:

Page 53: Shell programiranje [880,42 KiB]

SIGNALI I ZAMKE 47

Primjer 7.1: Upotreba naredbe trap

U gornjem primjeru program izvodi beskonačnu petlju i šalje «bell» znak na zaslon. Naredba trap na početku programa definira da će se nakon primanja signala 2 (INT) izvesi niz naredbi: "print primio signal 2; print; exit". Za isprobavanje ove skripte najbolje je da ju pokrenemo u pozadini i da sa kill –INT pošaljemo INT signal.

Naredba trap ima više ispravnih sintaksi:

a) trap “comm1; comm2;...” SIG1 SIG2 ... definira: izvedi naredbe comm1, comm2,...za signale SIG1 SIG2 ...b) trap “” SIG1 SIG2 ... ignoriraj signale SIG1 SIG2c) trap SIG1 SIG2 SIG2 obnovi reagiranje na signale nakon ignoriranja

Ignoriranje i ponovno definiranje signala možemo korisiti za pojedine odsječke shell programa. Nije potrebno da čitav shell program ignorira npr. INT signal.

Primjeri:trap “print uhvatio sam signaaaaaal” 1 2 3trap “print hvatam i izlazim; exit 1” 1 2 3trap “” 1 2 3

U gornjim primjerima najprije hvatamo signale 1 ili 2 ili 3 i samo ispišemo poruku, zatim u drugom primjeru hvatamo te iste signale ali nakon ispisivanja poruke izlazimi iz shell programa. U zadnjem primjeru od naredbe trap “” 1 2 3 naš shell program više neće reagirati na signale 1 2 3 (neće se ništa događati ako program dobije te signale).

#!/bin/ksh -p## trap.ksh## Ilustrira: signali i zamke

trap "print primio signal 2 ; print; exit" 2

while (true)do print "\a" sleep 5done

Page 54: Shell programiranje [880,42 KiB]

48 SHELL PROGRAMIRANJE

Naredbu trap obično stavljamo na početak shell programa, a unutarjednog shell programa možemo imati više trap naredbi.

Ako nakon primitka nekog signala želimo obaviti više naredbi, možemo u trap naredbi definirati poziv nekog novog shell programa. Npr.:

trap 'script.ksh $$ $c' INT

će definirati da se po primitku INT signala pozove skripta script.ksh i da joj se proslijede dva parametra PPID i vrijednost varijable c. Tu novu skriptu bi mogli pozvati i sa '. script.ksh'. U tom slučaju sve varijable (i čitavo okru­ženje) iz prvog shell programa je dostupno u script.ksh.

Vježbe:

7.1 Napišite shell program s beskonačnom petljom koji će na signal 2 ispisati poruku “Primio 2” i nastaviti s radom, a na signal 3 “Primio 3” i završiti.

7.2 U .profile dateci definirajte ime shell programa (npr. .exitksh) koji će se izvesti svaki puta kada napravimo logout. Napišite i primjer za .exitksh program. (Pomoć: od logout-a shell dobiva signal 0).

!!!

Page 55: Shell programiranje [880,42 KiB]

8 Funkcije

ksh i sh pružaju mogućnost definiranja i poziva funkcija. ksh također dozvo­ljava da se funkcije dijele između više korisnika i da se izgrađuju biblioteke funkcija.

8.1 Funkcije

Iz shell programa možemo pozivati drugi shell program ili bilo koji izvedivi program. (Svi uslužni programi su ujedno i ‘izvedivi programi’). Pozivanje drugih shell programa ujedno znači stvaranje novih procesa – što može značiti dugotrajan posao. Programe koje pozovemo iz našeg shell programa se izvode unutar novog procesa i u svom vlastitom okruženju. S našim shell programom dijele jedino varijable okruženja. Npr. iz programa koji se zove script1 možemo pozvati drugi shell program pod imenom script2:

if (( $# != 1 ))then

script2fi

Ako želimo definirati niz naredbi sa zajedničim imenom, a koje se mogu izvoditi unutar istog okruženja shell programa, možemo definirati i pozivati funkcije.

Izvođenje funkcija je u principu brže od poziva drugih programa jer ne treba stvarati novi proces. Prijenos parametara u i iz funkcije je nešto jednostavniji u odnosu na poziv drugih shell programa.

Definicija funkcije se mora nalaziti prije pozivanja same funkcije. Evo primjera definicije jedne funkcije:

function upotreba{

print –u2 “Upotreba: prog ime [parametri]exit 1

}

U gornjem primjeru je definirana funkcija upotreba. Samo definiranje funkcije ne znači i njeno pokretanje. Pokretanje (pozivanje) funkcije se obavlja navođenje imena funkcije. Npr.

if (( $# != 1 ))thenupotrebafi

Page 56: Shell programiranje [880,42 KiB]

50 SHELL PROGRAMIRANJE

Parametre definirane kod poziva funkcije dohvaćamo iz funkcije kao pozicione parametre $1, $2, ...Dakle, $1, $2 ... unutar funkcije više ne označavaju vrijednosti pozicionih partametara shell programa već parametara koje smo upotrebili kod poziva funkcije. Npr. ako pozovemo funkciju func1 s 3 parametra:

func1 aaa bbb ccconda će aaa biti iz funkcije vidljiv kao $1 itd.

U slijedećem primjeru definiramo funkciju potvrda i 2 puta je pozivamo.

Primjer 8.1: Funcija i njeni parametri

Varijable definirane u glavnom programu iz kojeg pozivamo funkciju su globalne varijable – što znači da su vidljive i unutar funkcija. Ne samo da su vidljive nego se njihove vrijednosti mogu mijenjati iz funkcija. To može biti jedan

#! /usr/bin/ksh -p

function potvrda{ print -n $1" " read odgovor if [[ $odgovor = [dD] ]] then return 0 else return 1 fi}

if potvrda "Obrisati datoteku? "then print "Brisem neku datoteku"fi

if potvrda "Zelite nastaviti? "then print "Nastavak rada"else print "Kraj rada"fi

Page 57: Shell programiranje [880,42 KiB]

FUNKCIJE 51

od načina na koji funkcija može vratiti neku vrijednost – što nije dobra praksa u programiranju.

Varijable definirane unutar funkcije s typeset su lokalne. Te varijable su vidljive jedino unutar funkcije, a ostaju nevidljive za glavni program.

Povratak iz funkcije se obavlja naredbom return, a ako želimo izaći sa posebnim povratnim kodom (kao u primjeru 8.1) koristimo return N.Ako pozovemo exit unutar funkcije, time završavamo izvođenje i funkciju i cijelog shell programa.

!!! sa exit završavamo funkciju, ali i shell program.

Definiranje zamki sa trap je lokalan za funkciju i neovisan o trap-u postavljenim u glavnom programu.

8.2 Biblioteke funkcija

Biblioteke funkcija su realizirane uz pomoć varijable FPATH. Varijabla FPATH definira PATH za pretraživanje kazala u kojima će se tražiti funkcije.

Ako smo npr. smjestili funkcije u kazalo koje smo nazvali /u2/func.d i napravili export FPATH=/u2/func.d, onda iz naših shell programa možemo pozivati funkcije koje nisu definirane u našim progamima već u datotekama smještenim u kazalu /u2/func.d. U tim datotekama imamo uobičajene definicije funkcija, a za svaku funkciju moramo imati posebnu datoteku, ili još bolje link, s istim imenom kao i funkcija.

U slučaju da koristimo FPATH, sve funkcije definirane u kazalima FPATH-a će se učitati prije izvođenja. Kod velikog broja funkcija u bibliotekama, obično ne koristimo sve funkcije nego samo neke od njih. Radi toga je nezgodno da shell pročita sve funkcije – koje možda nećemo ni koristiti => rješenje je autoload.

Naredba autoload func1 definira da funkcija postaje poznata (učitana) tek nakon 1. poziva => svako slijedeće pozivanje je brže, a funkcija se ne učitava ako je nikad ne pozovemo.

Vježbe:

8.1 Napišite shell program s funkcijom ispis. Funkcija ispis će na zaslon ispisati “ISPIS: …” pa sve argumente. Glavni program treba napraviti petlju koja

Page 58: Shell programiranje [880,42 KiB]

52 SHELL PROGRAMIRANJE

će se prolaziti 10 puta. U svakom prolazu petlje pozovite ispis i proslijedite kao argument broj prolaza kroz petlju.

8.2 Napišite program sa pozivom neke funkcije koja nije definirana u tom programu već ju dohvaćamo pomoću FPATH varijable.

8.3 Napišite funkciju rm koja će raditi «move» operaciju (naredba mv) u kazalo $HOME/trash. Parametri za poziv funkcije će biti imena datoteka i kazala. Isprobajte novu funkciju. Kako možete pozvati originalni rm?

++8.4 Napišite i testirajte program s funkcijom:substring var start_index end_index

koja će iz varijable var izvaditi substring koji počinje kod start_index a završava sa end_index (uključivo). Kako će te vratiti rezultat? Testirajte brzinu?

Page 59: Shell programiranje [880,42 KiB]

9 Važnije ugrađene naredbe

9.1 Set

Naredba set se koristi za veliki broj različitih poslova. Ovdje će se navesti samo oni poslovi koji su najkorisniji i koji se najčešće koriste.

Najjednostavnija upotreba naredbe set je za pregled svih varijabli i njihovih vri-jednosti. (Za pregled samo varijabli okruženja koristimo naredbu env). Npr. na mom UNIX-u dobivam:

# setENV=/.kshrcERRNO=9FCEDIT=/bin/edHOME=/IFS=' 'LD_LIBRARY_PATH=/usr/openwin/libLINENO=1LOGNAME=rootMAIL=/var/mail//rootMAILCHECK=600MANPATH=/usr/share/man:/opt/local/man:/usr/openwin/manOLDPWD=/usr/rbinOPTIND=1PATH=/usr/bin:/usr/sbin:/opt/local/bin:/usr/local/sbin:/usr/local/bin:/usr/openwin/binPPID=1752PS1='# 'PS2='> 'PS3='#? 'PS4='+ 'PWD=/home/damir/cmupw_dRANDOM=13650SECONDS=1875SHELL=/sbin/shSSH_CLIENT='161.53.72.31 3976 22'SSH_TTY=/dev/pts/5TERM=vt100TMOUT=0TZ=METUSER=root_=set

Page 60: Shell programiranje [880,42 KiB]

54 SHELL PROGRAMIRANJE

Za interaktivno ili programsko postavljanje raznih opcija ksh-a koristimo sintaksu set –o … Evo nekoliko najčešćih opcija:

set –o vi aktiviranje mehanizma pamćenja i vi editiranja

set –o emacs aktiviranje mehanizma pamćenja i emacs editiranja

set –o noclobbernemoj obrisati postojeću datoteku sa >

set -o noglob nemaj zamijeniti * sa imenima datoteka

set –o ignoreeof ignoriraj EOF znak ( ^D ) kao naredbu za logout

set –o verbose prikaži ulazni redak nakon čitanja

set –o xtrace prikaži izvođenje svake naredbe

Za postavljanje nekih opcija može se koristiti i skraćena sintaksa. Tako npr. ako hoćemo postaviti xtrace i verbose opcije možemo koristiti naredbu set –xv.

!!! Za resetiranje opcija koristimo set +o … sintaksu.

Npr. set +o xtrace.

Posebno interesantne su opcije verbose i xtrace koje se koriste kod debugiranja shell programa. Nakon uključivanja ovih opcija na stderr ćemo dobiti dodatne informacije o izvođenju našeg shell programa. Ove opcije možemo koristiti za cijeli program ili samo za jedan dio programa. Česta je praksa da se kod razvijanja složenijih shell programa na početku programa stavi set –xv, a kasnije, kada je program iztestiran, taj se redak može staviti u komentar. Pogledajte korištenje –vx opcije u primjeru 9.1.

Naredbu set koristimo i kod definiranja polja varijabli (vidi prethodna poglavlja):

set –A polje a b c d

Vrlo čest i korisna upotreba naredbe set je postavljenje pozicionih parametara. Postavljanje pozicionih parametara je moguće sa:

set arg1 arg2 arg3 ....

Nakon ove naredbe zaboravljaju se stvarni pozicioni parametri, a ovim smo definirali nove vrijednosti za njih – u gornjem primjeru arg1, arg2, itd. Ovakvo korištenje naredbe set možemo trebati kada neki redak treba rastaviti na riječi. Npr. vrlo koristan je obrazac, već spomenut kod while petlje, koji koristimo za čitanje ulazne datoteke redak po redak i za neku obradu ulaznih redaka:

Page 61: Shell programiranje [880,42 KiB]

VAŽNIJE UGRAĐENE NAREDBE 55

Primjer 9.1: xv opcije i rastavljanje na riječi sa setGornji program bi pozvali sa prog < ulazna_datoteka. U gornjem primjeru naredba set se koristi za razdvajanje ulaznog retka na riječi. Najprije se pročita ulazni redak s naredbom read i spremi u uobičajenu (eng. default) varijablu REPLY, poziva se set i prikazuje prva i četvrta riječ iz ulaznog retka. (U stvarnim primjenama ovdje bismo imali neku složeniju obradu). While petlja omogućuje da obradimo sve retke iz ulazne datoteke.

Ako bi u datoteci ulazna_datoteka imali dva retka:

pero peric 123 fer

ana anic 456 pmf

nakon pokretanja bismo dobili slijedeći izlaz:$ prog < ulazna_datotekawhile read # citaj redak po redakdo set $REPLY # rastavi redak na rijeci print $1 $4 # obradi ulazni redakdone+ read+ set pero peric 123 fer+ print pero ferpero fer+ read+ set ana anic 456 pmf+ print ana pmfana pmf+ read

Retci označeni s «+» («+» je niz definiran u varijabli PS4) prikazuju izvođenje svake naredbe – posljedica x opcije , a retci bez plusa na početku, prikazuju koji bi izlaz dao program. Radi v opcije čitav program se prikazuje na početku izvođenja.

#! /usr/bin/ksh

set -vxwhile read # čitaj redak po redakdo

set $REPLY # rastavi redak na riječiprint $1 $4 # obradi ulazni redak

done

Page 62: Shell programiranje [880,42 KiB]

56 SHELL PROGRAMIRANJE

Popis riječi iza set možemo dobiti na razne načine. Npr. sa $var , kao u primjeru 8.1, ili sa supstitucijom naredbe $(...) ili na bilo koji drugi način.

9.2 Shift

Naredba shift se koristi za pomicanje pozicionih parametara za jedno mjesto ulijevo. Uzmimo za primjer situaciju u kojoj su definirani pozicioni parametri: P1 P2 P3 i P4. Nakon poziva naredbe shift pozicioni parametri će biti P2 P3 P4 – dakle prvi pozicioni parametar će postati P2, a P1 će nestati:

Prije poziva shift$1 $2 $3 $4 $#P1 P2 P3 P4 4

Nakon poziva shift

$1 $2 $3 $4 $#P2 P3 P4 3

Naredba shift ujedno mijenja sistemsku varijablu $#.

Iza shift možemo imati broj za koliko mjesta pomićemo parametre. Npr. shift 3 će pomaknuti lijevo tri parametra.

Naredba shift se obično koristi u procesiranju pozicionih parametara. Prvo obrađujemo prvi pozicioni parametar, zatim napravimo shift, pa ponovo obradjujemo prvi pozicioni parametar jer smo u njega dobili slijedeći neobrađeni. Obradu treba prekinuti kada $# postane manji od 1. Evo jednog primjera:

Primjer 9.2: Upotreba naredbe shift

while (( $# > 1 ))do ... # napravi nešto s $1 shift # nakon shift, slijedeći parametar postaje $1done

Page 63: Shell programiranje [880,42 KiB]

VAŽNIJE UGRAĐENE NAREDBE 57

9.3 Eval

Problem: Napišite naredbu s kojom ćemo iz shell programa ispisati vrijednost zadnjeg parametra bez da koristimo petlju.

Ne ide: $$# ili ${$#} ili nešto slično.

Kad ovo pokušavamo riješiti izgleda kao da treba dva puta proći kroz redak. U prvom prolazu treba izračunati broj parametara N (spremljeno u $#), a zatim tu vrijednost N uzeti kao broj za zadnji parametar $N.

Kada imamo dojam da treba dvostruki prolaz kroz redak koristimo naredbu eval:

eval print ‘$’$#

Prvi $ mora biti u jednostrukim apostrofima jer bi $$ značilo trenutni PID.

Naredba eval, u stvari, omogućuje inirektno definiranje varijabli ili parametara.

9.4 Exec

Naredba exec se koristi kad želimo zamijeniti trenutni interaktivni shell (ili shell program) s nekim drugim programom:

exec program

Npr. jedan moj kolega s posla ne voli što je default shell za root korisnika sh, pa odmah nakon prijave utipkava # exec zsh. Kod ovakve upotrebe exec-a ne stvara se novi proces kao što bi se dogodilo da smo samo pokrenuli novi proces sa npr. # zsh nego se postojeći zamijenjuje sa zsh.

Druga upotreba naredba exec je kad želimo otvoriti više datoteka iz jednog shell programa. Slijedi nekoliko primjera:

exec 3< ulaz otvori datoteku ulaz kao opisnik 3

exec 4> izlaz otvori datoteku izlaz kao opisnik 4

exec 5<&0 opisnik 5 je kopija od 0

exec 3<&- zatvori opisnik 3

Slijedeći primjer ilustrira upotrebu naredbe exec i upotrebu naredbi već spomenutih ranije: read –u i print –u. Program uspoređuje dvije datoteke redak po redak i ako su retci isti prepisuje redak u datoteku match, a ako reci

Page 64: Shell programiranje [880,42 KiB]

58 SHELL PROGRAMIRANJE

nisu isti prepisuju se u drugu datoteku nomatch. Uočite da je s exec naredbom najprije otvoreno 4 datoteke. Datoteke se čitaju s read –uN naredbom, gdje je N opisnik kojeg smo prethodno dobili s exec.

Primjer 9.3: Upotreba exec naredbe za višestruki U/I

Vježbe:

9.1 Napišite program koji čita retke uz stdin i na zaslon prikazuje prvu i treću riječ iz svakog retka.

9.2 Isprobajte naredbe:

m1=goodby

m2=hello

var=m2

#! /usr/bin/ksh -p

if (( $# != 2 ))then print -u2 "Upotreba: $0 file1 file2" exit 1fi

exec 3< $1exec 4< $2exec 5> matchexec 6> nomatch

while read -u3 line1do read -u4 line2 if [ "$line1" = "$line2" ] then print -u5 "$line1" else print -u6 "$line1 ----###---- $line2" fi

Page 65: Shell programiranje [880,42 KiB]

VAŽNIJE UGRAĐENE NAREDBE 59

eval print ‘$’$var

Objasnite rezultat. Da li bi se moglo drugačije rješiti?

+9.3 Modificirajte program conv2 u conv3 tako da kao parametre čitamo ime varijable cp1250, cro7... koje će biti definirane u programu. Te varijable sadrže nizove po kojima se obavlja konverzija. Pomoć: upotrebite naredbu eval.

Page 66: Shell programiranje [880,42 KiB]

10. Koprocesi

Iz shell progama možemo pokrenuti više programa (procesa) koji će se odvijati u pozadini. Kao i kod interaktivnog rada dovoljno je da iza UNIX naredbe stavimo znak "&". Npr.

…sort –o big_file_sorted big_file &…

Naredba sort će se izvoditi u pozadini što znači da se stvara novi proces, a glavni program ne čeka njegovo završavanje već nastavlja s izvođenjem slijedeće naredbe iza sort.

Na taj način dobivamo istovremeno (paralelno, konkurentno) izvođenje više procesa.

Komunikacija između tih istovremenih procesa je svedena jedino na slanje i obradu signala. Ako se pojavi potreba za bogatijom komunikacijom između procesa, moramo korisiti koprocese. Koprocese koristimo i u situacijama kada želimo napraviti omotač (eng. wrapper) oko postojeće naredbe i definirati joj drugačije sučelje.

Koproces je skup naredbi koji se odvija u pozadini, a s kojim je moguća potpuna komunikacija.

Za pokretanje koprocesa iza naredbe stavljamo operator od dva znaka |&. Npr. U slijedećem primjeru pokrećemo linijski editor ed kao koproces i nastavljamo mu slati naredbe iz našeg shell programa.

ed – pwfile |&print –p /ana/read –r –p lineprint –r - $line

U gornjem primjeru koproces se sastoji od samo jedne naredbe. Koproces se može sastojati od više naredbi koje stavljamo unutar okruglih zagrada – što je uobičajeni način za grupiranje naredbi koje se pokreću u podshell-u. Npr. slijedeći primjer prikazuje koproces od tri naredbe:

( print "Koproces: pokrenut" read message print "Koproces: $message") |&

Program koji je pokrenuo koproces može koprocesu slati poruke sa print –p a iz njega čitati poruke s read –p naredbama.

Za uspješno komuniciranje s glavnim programom koproces mora zadovoljiti slijedeće uvjete:

- slati svoje poruke na stdout

Page 67: Shell programiranje [880,42 KiB]

KOPROCESI 61

- imati ‘\n’ na kraju svake poruke

- poslati poruke odmah (bez bufferiranja)

Evo jednog kompletnijeg i ozbiljnijeg primjera koji ilustrira upotrebu koprocesa. Program obrađuje ulaznu datoteku koja sadrži popis UNIX korisnika, popis aliasa ili sl. Svaki korisnik je zapisan u jednom retku zajedno s nekim drugim podacima. Osim ulazne datoteke, imamo i datoteku (popis_imena_za_ obrisati) koja sadrži imena UNIX korisnika koje treba obrisati iz ulazne datoteke. Odredili smo da imena UNIX korisnika zadajemo kao pozicione parametre. Program bismo mogli pozvati na slijedeći načina:

rmentry $(< popis_imena_za_obrisati)što je, u stvari, isto kao rmentry ime1 ime2 ime3 …

Primjer 10.1: Koprocesi u akciji

#! /usr/bin/ksh -p## rmentry.ksh Brise retke iz datoteke

UPOTREBA="rmentry entry1 [entry2 ...]"FILE=afileed - $FILE |& # Koprocesinteger counter=0for entrydo print -p /$entry/ read -p answ if [[ $answ = '?' ]] then print -u2 "Ne mogu naci redak s $entry" continue else print -p "d" (( counter += 1 )) fidoneprint -p "w"print -p "q"print -u2 "Obrisano $counter entry-a"exit 0

Page 68: Shell programiranje [880,42 KiB]

62 SHELL PROGRAMIRANJE

Ključne su naredbe ed - $FILE |& s kojim započinjemo linijski editor ed kao koproces. Nakon toga, za svako ime pokrećemo naredbu print –p /$entry/ s kojom tražimo u ulaznoj datoteci redak s tim imenom, a zatim sa print –p "d" brišemo taj redak. Na kraju zatvaramo i zapisujemo editiranu ulaznu datoteku sa print –p "w" i print –p "q". Važno je primjetiti da ono što pišemo iza print –p su, u stvari, editorske naredbe čija sintaksa ovisi o ed, odnosno u općem slučaju o koprocesu koji koristimo.

Ovakav način obavljanja ovog posla daleko je učinkovitiji od nekih drugih rješenja sa npr. grep -v ili slično. Ulazna datoteka je učitana samo jednom i čitava obrada se obavlja u memoriji sve dok nismo obradili posljednjeg iz liste.

Iz jednog shell programa moguće je pokrenuti više od jednog koprocesa. Nakon pokretanja svakog koprocesa moramo napraviti redirekciju:

(.....) |& # prvi koproces

exec 4>&p; exec 5<&p(.....) |& # drugi koproces

exec 6>&p; exec 7<&pprint –u4 ....ili date >&5 # pišemo u prvi

read –u5 # čitamo iz prvog

print –u6 ... # pišemo u drugi

read –u7 # čitamo iz drugog

U gornjem nizu od 8 naredbi napravili smo slijedeće:

1. Napravi prvi koproces

2. Definiraj opisnik 4 za pisanje u taj koproces, a opisnik 5 za čitanje iz tog koprocesa.

3. U retku 3 stvaramo drugi koproces.

4. U retku 4 definiramo opisnike 6 i 7 za komunikaciju s drugim koprocesom.

U recima 6 7 i 8 pišemo ili čitamo iz tih koprocesa.

Zatvaranje komunikacije i otvorenih opisnika obavljamo sa npr. exec 5<$-