Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web servers, web development, networking and security services. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

Korn Shell (ksh) programiranje

Ovo je najviši nivo mog stabla „Uvod u Korn Shell programiranje“. Korn Shell je ’shell skripting’ jezik, a takođe i shell za prijavljivanje (logovanje) na korisničkom nivou. On je ujedno i nadkolekcija POSIX.1 kompatibilnog shell-a, što je odlično za obezbeđivanje prenosivosti.


Zbog čega skriptovanje?

Kada je dobro urađeno, skriptovanje je brz i lak način za „završavanje posla“, bez uobičajene „piši program, kompajliraj, testiraj, otklanjaj greške“ gnjavaže sa pisanjem u C-u, ili nekom drugom kompajlerskom jeziku. Ono je jednostavnije od C-a iz više razloga:

  1. Komande za skriptovanje teže da budu čitkije od programskog koda niskog nivoa (sa izuzetkom pearl-a)
  2. Jezici za skriptovanje obično dolaze sa uključenim moćnim alatima
  3. Nema faze „kompajliranja“, tako da „podešavanja“ mogu da se izvode brzo.

UNIX teži da pomeri 2. mesto do krajnjih granica, pošto standardno dolazi u paketu sa „moćnim alatima“ koji mogu biti međusobno povezani cevima ili nekim drugim mehanizmima, da sa malo vremena utrošenog na programiranje dobijete rezultat kakav želite. Možda nije efikasno kao potpuno kompajlirano rešenje, ali veoma često može „završiti posao“ u nekoliko sekundi rada, u poređenju sa 1 sekundom, ili manje, za kompajlirani program.

Brzo skriptovano rešenje se može upotrebiti kao prototip. Zatim, nakon što ste neko vreme uspešno koristili prototip, i pošto ste razvili ponašanje svog programa kojim su vaši krajnji korisnici najzadovoljniji, možete se vratiti na početak i isprogramirati brže i robusnije rešenje u nekom jeziku nižeg nivoa.

To ne znači da skripte ne mogu biti robusne! Skriptovanjem je moguće rešiti veći deo provera grešaka. Nažalost, nije uobičajena praksa da se tako radi.


Šta možete raditi ksh-om?

Đavolski mnogo stvari!

Imate pristup celokupnoj paleti UNIX alata, i još nekim divnim unutrašnjim resursima.

Uopšteno govoreći, UNIX skriptovanje je stvar korišćenja raznih „command line“ alatki, po potrebi, sa shell-om kao sredstvom za olakšavanje komunikacije između svaka dva koraka.

Nažalost, izvršavanje svih ovih zasebnih „spoljnih“ programa može povremeno izazvati da stvari prilično sporo rado. Ovo je i razlog što ksh ima par stvari više „ugrađenih“ u sebe, od starijeg 'sh'-a.

Zašto za programiranje izabrati ksh, a ne bilo koji drugi shell?

Bourne shell je mnogo godina bio ONAJ PRAVI „standardni“ jezik za UNIX shell skriptovanje. Ipak, manjkaju mu neke stvarčice koje bi bile veoma korisne, na osnovnom nivou. Neke od njih su nešto kasnije dodate C-shell-u (csh). U svakom slučaju, csh nije poželjan za korišćenje u programiranju iz različitih razloga.

Na sreću, ksh donosi većinu stvari za koje ljudi govore da ih csh ima, a sh ih nema. Tako da je ksh postao osnova za „POSIX shell“. Ovo znači da svi valjani POSIX-kompatibilni sistemi MORAJU IMATI nešto kompatibilno, iako je to sada nazvano „sh“ poput starog Bourne shell-a. (Na primer, /usr/xpg4/bin/sh, je VEZA ka /bin/ksh, na solaris-u!) Još preciznije, ponašanje POSIX-kompatibilne ljuske je propisano standardom „IEEE POSIX 1003.2“.

Uzgred budi rečeno: „Korn Shell“ je napisan od strane „Davida Korn-a“, negde oko 1982. u AT&T laboratorijama. Sada možete slobodno preuzeti ceo izvorni kod sa sajta AT&T, ako niste dovoljno srećni da koristite OS u koji je već uključen ksh. Čak je u pitanju i „otvoren kod“!


Naslovi poglavlja

Sada dolazimo do pravih stvari. Molim vas, upamtite: ova poglavlja bi trebalo da čitate redom. Ukoliko ne budete razumeli sve stvari iz prethodnog poglavlja, možete kasnije biti prilično zbunjeni.


Ovaj materijal je zaštićen autorskim pravima, Philip Brown 2000. - 2011.


Spremnost za Ksh

Zdravo, i dobrodošli u uvod u programiranje u Korn shell-u, POZNATOM KAO POSIX.1 shell.

Ovo je prvi deo šireg tutorijala. Ovde se pretpostavlja da želite da naučite kako da zaista budete programer u ksh-u, za razliku od nekoga ko samo na brzinu ubacuje razne stvari u fajl sa kodom i zaustavlja se na tome, sve dok mu to tako funkcioniše.

Konkretno u ovom poglavlju polazi se od pretpostavke da ste se pre ovoga sh programiranjem bavili u minimalnoj meri, ili nimalo, tako da ono sadrži dosta opštih stvari. Ovde su izložene najvažnije stvari koje treba da znate i uradite, pre nego što stvarno postanete ozbiljni po pitanju shell skriptovanja.

Korak 0. Naučite kako da unosite tekst.

Ne, ja mislim VALJANO, i nesvesno. Trebalo bi da budete u stanju da kucate brže nego što možete da pišete, a da se ne znojite dok to radite. Razlog za ovo je što dobra programerska praksa podrazumeva mnogo kucanja. Nećete moći da primenjujete najbolja praktična rešenja, ako ste previše obuzeti razmišljanjem "Kako da iskoristim što je manje moguće karaktera, da završim ovaj posao?".

Korak 1. Naučite kako da koristite program za uređivanje teksta.

Ne, nemojte microsoft word, ili word perfect. To su programi za obradu tekstualnih sadržaja, tzv. “word processor”-i. Ja ovde govorim o nečemu malom i brzom što omogućava lako prikazivanje čistog teksta. [Imajte u vidu da za emacs ne važi ‘mali’, ‘brz’ ili ‘živahan’ :-)]

Moraćete da budete veoma komforni u radu sa vašim izabranim tekst editor-om, jer ćete tako praviti shell skripte. Sve navedene primere treba staviti u neki fajl. Njega zatim možete pokrenuti sa "ksh file".
Ili to uradite na zvaničniji način; Stavite dolenavedena uputstva, baš kao što stoje, u fajl, i zatim pratite ta uputstva.

#!/bin/ksh
# gornji tekst mora uvek biti uvek prva linija koda. Ali inače, linije
# koje počinju znakom '#' su komentari. Oni ništa ne rade.
# Ovo je jedini put da ću ja ubaciti liniju '#!/bin/ksh' bit. Ali
# ONA JE POTREBNA U SVAKOM PRIMERU, osim ako ne želite da pokrećete primere
# sa 'ksh filename' svaki put.
#
# Ako iz nekog čudnog razloga kod vas ksh nije u /bin/ksh, izmenite
# gornju putanju, prema potrebi.
#
# Zatim izvršite komandu 'chmod 0755 name-of-this-file'. Nakon toga,
# moći ćete da koristite ime fajla direktno kao komandu

echo Yeup, imate skriptu koja radi!

Korak 2. Razumite promenljive.

Nadamo se da ste već shvatili ideju promenljive. To je mesto gde možete sačuvati vrednost, a zatim primenjivati razne operacije na "bilo čemu što se tu nalazi", umesto da koristite direktno samu vrednost.

U shell skriptama, promenljiva može da sadrži kolekciju slova i/ili brojeva [tzv. ‘string’], kao i čiste brojeve.

Promenljivoj dodeljujete vrednost koristeći

variablename="ovde se nalazi neki niz znakova (string)"
 ILI
variablename=1234

Onome što se nalazi UNUTAR promenljive pristupate stavljanjem znaka “dolar” ($) ispred imena promenljive.

echo $variablename
 ILI
echo ${variablename}

Ako imate SAMO broj u promenljivoj, možete primenjivati matematičke operacije na nju. Ali na to ćemo doći kasnije u ovom tutorijalu.

Korak 3. Stavljajte sve u odgovarajuće promenljive

Pa, dobro, ne baš SVE :-). Ali pravilno imenovane promenjive čine skriptu lakše čitljivom. Zaista ne postoji neki 'jednostavan' primer za ovo, jer je to "očigledno" samo u velikim skriptama. Pa zato, ili mi verujte na reč za to, ili prestanite sa čitanjem i idite negde drugde, odmah!

Primer "pravilne" prakse imenovanja promenljivih:

# Dobro, ova skripta ne radi ništa korisno, ona je ovde samo u svrhu demonstracije.
# i, obično bih ubacio više sigurnosnih provera, ali ovo je brzi primer..
INPUTFILE="$1"
USERLIST="$2"
OUTPUTFILE="$3"

count=0

while read username ; do
    grep $username $USERLIST >>$OUTPUTFILE
    count=$(($count+1))
done < $INPUTFILE
echo user count is $count

Iako skripta za vas možda još nije potpuno čitljiva, mislim da ćete se složiti da je MNOGO jasnija od sledeće;

i=0
while read line ; do
    grep $line $2 >> $3
    i=$(($i+1))
done <$1
echo $i

Obratite pažnju na to da '$1' znači prvi argument u vašoj skripti.
'$*' znači “svi argumenti zajedno”
‘$ #’ znači "koliko argumenata ima ovde?"

Korak 4. Poznajte svoje navodnike

Vrlo je važno znati kada, i koji tip, navodnika treba upotrebiti.
Generalno, navodnici se koriste da grupišu stvari zajedno u jedinstvenu celinu.

Jednostruki navodnici su bukvalni citati.
Kod duplih navodnika sadržaj se može proširiti.

echo "$PWD"

prikazuje na ekranu vaš trenutni direktorijum

echo '$PWD'

prikazuje na ekranu niz znakova “$PWD”

echo $PWDplusthis

ne prikazuje NIŠTA. Ne postoji takva promenljiva “PWDplusthis”

echo "$PWD"plusthis

prikazuje vaš trenutni direktorijum, i niz znakova "plusthis" odmah iza toga. Ovo možete postići i alternativnim oblikom korišćenja promenljivih,

echo ${PWD}plusthis

Postoji još i nešto što se ponekad zove `kontra navodnici`, ili ` backtick`: Ovo se ustvari ne koristi za citiranje stvari, već da se procene i izvrše komande.


POČETAK tutorijala
Naredno poglavlje: Ksh osnove: Petlje i uslovna grananja

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Ksh osnove

Ovo je stranica koja će vas na brzinu provesti kroz problematiku "kontrole programskog toka”, u slučaju da ste potpuno neupućeni u shell programiranje. Osnovni načini da se oblikuje neki program, su programske petlje i uslovna grananja toka (kondicionali). Uslovno grananje kaže “izvrši ovu komandu ako (IF) je neki uslov ispunjen”. Petlja kaže “ponavljaj ove komande” (obično, dok se ne ispuni neki uslov, a zatim prestajete sa ponavljanjem).


Uslovna grananja

IF

Osnovni tip uslovnog grananja je "if".

if [ $? -eq 0 ] ; then
    print dobro nam ide
else
    print nešto je omanulo
fi

IF (ako) je promenljiva $? jednaka 0 (nuli), THEN (onda) program prikazuje poruku na ekranu. ELSE (u suprotnom), prikazuje drugu poruku. Za vašu informaciju, "$?" proverava izlazni status poslednje pokrenute komande.

'fi' koje se nalazi u poslednjem redu je neophodno. Ono vam omogućava da zajedno grupišete više stvari. Možete imati više stvari izmedju if i else, ili između else i fi, ili oboje. Možete čak i da preskočite 'else' u potpunosti, ako vam ne treba alternativni slučaj.

if [ $? -eq 0 ] ; then
    print dobro nam ide
    print ovde možemo da radimo koliko god hoćemo
fi

CASE

Komanda case funkcioniše poput komande 'switch' u nekim drugim jezicima. Polazeći od određene promenljive, prelazi na poseban skup komandi, zavisno od vrednosti te promenljive.

Mada je, spolja gledano, sintaksa slična C-u, ipak postoje neke značajne razlike;

echo input da ili ne
read  answer
case $answer in
    da|Da|d)
        echo odgovor je pozitivan
        # the following ';;' is mandatory for every set
        # of comparative xxx)  that you do
        ;;
    ne)
        echo odgovor je 'ne'
        ;;
    q*|Q*)
        # pretpostavimo da korisnik hoće da izađe iz programa
        exit
        ;;
       
    *)
        echo Ovo je podrazumevana odredba. Nismo sigurni zašto ili
        echo šta bi to neko kucao, ali mogli bismo preuzeti
        echo neku akciju ovde
        ;;
esac

Petlje

WHILE

Osnovna petlja je 'while' petlja; "while" (dok) je neki uslov ispunjen, nastavlja da se ponavlja.

Postoje dva načina da se neka petlja zaustavi. Očigledan način je to da se sama zaustavlja kada 'nešto' više nije tačno. Drugi način je zaustavljanje pomoću komande 'break'.

keeplooping=1;
while [[ $keeplooping -eq 1 ]] ; do
    read quitnow
    if [[ "$quitnow" = "yes" ]] ; then
        keeplooping=0
    fi
    if [[ "$quitnow" = "q" ]] ; then
        break;
    fi
done

UNTIL

Druga vrsta petlje u ksh-u je 'until' petlja. Razlika između nje i 'while' petlje je u tome što 'while' petlja podrazumeva ponavljanje dok je neki uslov ispunjen, a 'until' petlja se ponavlja sve dok se neki uslov ne ispuni.

until [[ $stopnow -eq 1 ]] ; do
    echo izvrši ovo samo jednom
    stopnow=1;
    echo ne bi trebalo da se ponovo nađemo ovde.
done

FOR

"for petlja", je "ograničena petlja". Ona se ponavlja određen broj puta, da uklopi određen broj stavki. Jednom kada pokrenete ovu petlju, broj njenih ponavljanja ostaje fiksan.

Osnovna sintaksa je

for var in jedan dva tri ; do
    echo $var
done

Koje god ime odabrali za promenljivu , umesto navedenog 'var', ona će biti ažurirana svakom od vrednosti koje slede posle službene reči "in". Dakle, gornja petlja će na ekranu prikazati

jedan
dva
tri

Ali, takođe, ove vrednosti promenljive možete dobiti i definišući listu stavki. Vrednosti iz liste će biti proverene SAMO JEDNOM, onda kada pokrenete izvršavanje petlje.

list="jedan dva tri"
for var in $list ; do
    echo $var
    # Napomena: Menjanje ovoga NE utiče na elemente petlje
    list="nolist"
done

Dve stvari koje se mogu primetiti su:

  1. Ona i dalje na ekranu prikazuje "jedan" "dva" "tri"
  2. NEMOJTE stavljati pod navodnike "$list", ako želite da komanda 'for' koristi više stavki

Ukoliko ste upotrebili "$list" u 'for' liniji, program će na ekranu prikazati JEDAN RED, "jedan dva tri".


POČETAK tutorijala
Naredno poglavlje: Napredni operatori za rad sa promenljivama Prethodno poglavlje: Pre nego počnete

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Napredna upotreba promenljivih

Velike zagrade

Uporedite izlaze koji se dobijaju sa sledeće dve linije:>

dva=2
print jedan$dvatri
print jedan${dva}tri

Ne postoji promenljiva nazvana "dvatri", pa zato ksh podrazumeva da je to prazna vrednost, kod prikazivanja na ekranu prve linije. Međutim, kada upotrebite velike zagrade da jasno pokažete ksh-u {ovo je ime promenljive}, on razume da želite da umetnete promenljivu “dva” među ona druga slova.

Nizovi

Da, MOŽETE koristiti nizove u ksh-u, za razliku od bourne shell-a. Sintaksa je sledeća:

# Ovo je jedan OPCIONI način da na brzinu poništite prethodne vrednosti
set -A array
#
array[1]="jedan"
array[2]="dva"
array[3]="tri"
tri=3

print ${array[1]}
print ${array[2]}
print ${array[3]}
print ${array[tri]}  #Ovo se tumači kao array[3]

Obratite pažnju na to da ksh automatski dereferencira imena unutar [], uzimajući da su to vrednosti promenljivih. Nažalost, izgleda da ksh ne obrađuje asocijativne nizove (pohranjivanje vrednosti indeksiranih stringom 'abcd', umesto numeričkog indeksa).

Specijalne promenljive

Postoje i neke "specijalne" promenljive kojima ksh sam dodeljuje vrednosti. Evo onih koje smatram za interesantne

Podešavanja pomoću promenljivih

Oba shell-a, i bourne shell i KSH, imaju puno neobičnih malih podešavanja koja možete izvesti pomoću operatora ${}.
Ispod su navedena ona koja se meni dopadaju.


Da dodelite podrazumevanu vrednost, ako i SAMO ako promenljiva nije već podešena, koristite ovaj konstrukt:

APP_DIR=${APP_DIR:-/usr/local/bin}

(važi samo za KSH)
Možete takođe biti moderni, pokrećući neku konkretnu komandu da generiše određenu vrednost. Na primer

DATESTRING=${DATESTRING:-$(date)}

(važi samo za KSH)
Da izbrojite broj karaktera sadržanih u stringu koji čuva neka promenljiva, koristite ${#varname}.

echo broj karaktera u promenljivij stringvar je ${#stringvar}

(važi samo za KSH)
Da izdvojite karaktere iz vrednosti neke promenljive, koristeći shell upoređivanje pomoću “džoker znakova” (wildcard matching):
(zapamtite da korišćenje dupliranog džoker znaka znači "pohlepno traženje (greedy match)": tražite najdužu vrednost koja se poklapa. Pri čemu je za pojedinačne karaktere podrazumevano da se jednostavno otkine prvi pogodak)

$ PATHNAME=/path/to/file

$ print ${PATHNAME#*/}
path/to/file
$ print ${PATHNAME##*/}
file

$ print ${PATHNAME%/*}
/path/to
$ print ${PATHNAME%%/*}
(ništa! Program je uklonio celokupnu putanju! :)

Gorenavedeno je korisno za interne shell zamene za komande "dirname" i "basename"; a ovi operatori imaju, isto tako, i druge primene.


POČETAK tutorijala
Naredno poglavlje: POSIX.1 alati Prethodno poglavlje: Ksh osnove

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Ksh i POSIX alati

POSIX.1 (ili je to, možda POSIX.2?) kompatibilni sistemi (npr. najnovije verzije UNIX-a) dolaze sa određenim neverovatno korisnim alatima. Ukratko, to su:

cut, join, comm, fmt, grep, egrep, sed, awk

Svaka od ovih komandi (i još mnoge druge) može biti iskorišćena u vašoj shell skripti za manipulaciju podacima.

Neke od ovih alata su i programski jezici, sami po sebi. Sed je prilično složen, a AWK je ustvari sopstveni mini programski jezik. Tako da ću ja samo preleteti preko nekih osnovnih saveta i trikova.

cut

"cut" je mala, siromašna verzija onoga za šta većina ljudi koristi awk. Ovaj alat će "iseći" neki fajl u kolone, i to samo kolone koje navedete. Njegovi nedostaci su:

  1. Prozbirljiv je u pogledu redosleda argumenata. MORATE upotrebiti -d argument pre -f argumenta
  2. Podrazumeva IZRIČITO tabulator, kao svoj razgraničivač kolona.

Prvi je samo iritirajući. Drugi nedostatak je značajan, ako želite da budete fleksibilni oko fajlova. Ovo je razlog zašto se više koristi AWK, čak i kao ovako trivijalan operator: Awk podrazumeva da je dopušteno da BILO KAKAV prazan prostor definiše kolone.

join

join je sličan komandi "database join", osim što radi sa fajlovima. Ukoliko imate dva fajla, oba sa informacijama poređanim po korisničkom imenu, možete ih “spojiti” (join) u jedan fajl, AKO i SAMO AKO su takođe sortirani po tom istom polju. Na primer

john_s John Smith

u jednom fajlu, i

john_s 1234 marlebone rd

biće spojeni i napraviće jedinstvenu liniju,

john_s John Smith 1234 marlebone rd

Ukoliko fajlovi nemaju već zajedničko polje, možete koristiti ili alat paste da spojite ta dva fajla, ili možete svakom fajlu dodeliti brojeve linija, pre nego ih spojite, sa

cat -n file1 >file1.numbered

comm

Ja "comm" posmatram kao da je to, na neki način, skraćenica od "compare". Ali, tehnički, to znači "common lines" (zajedničke linije). Prvo, pokrenite bilo koja dva fajla kroz "sort". Zatim možete pokrenuti 'comm fajl1 fajl2' da dobijete informaciju koje linije se nalaze SAMO u fajl1, ili SAMO u fajl2, ili oboje. Ili možete zadati bilo koju od kombinacija.

Na primer

comm -1 fajl1 fajl2

znači "NE prikazuj mi linije koje su SAMO u fajl1." Što je isto kao da se kaže "Pokaži mi linije koje se nalaze SAMO u fajl2", i, uz to, "Pokaži mi linije koje se nalaze u OBA, fajl1 i fajl2".

fmt

fmt je jednostavna komanda koja uzima neki informativni tekstualni fajl, i fino ga “prelama” (radi prelom teksta), tako da se tekst uklopi u terminal fiksne širine. U redu, ovo nije toliko korisno u shell skriptama, ali je dovoljno lepo i zanimljivo, da sam prosto želeo da ga pomenem :-)

Komanda pr je na sličan način korisna. Samo što je fmt više orijentisana na paragrafe, a pr je posebno namenjena za formatiranje strana-po-strana.

grep i egrep

Ovo su dve komande koje imaju mnogo ozbiljniju primenu od one koja je ovde prikazana. Ali, uopšteno govoreći, možete ih koristiti da pronađete određene linije unutar nekog fajla (ili fajlova), koje sadrže vama bitne informacije.
Jedna od očiglednijih njihovih primena je pronalaženje korisničkih informacija. Na primer, komanda

grep joeuser /etc/passwd

će vam dati liniju u fajlu passwd, koja se odnosi na nalog 'joeuser'. Ako ste prigodno paranoični, ustvari ćete koristiti

grep '^joeuser:' /etc/passwd

da budete sigurni da program neće ujedno pokupiti i informacije o nalogu 'joeuser2'.

(Napomena: ovo je samo primer: često je awk pogodniji alat od grep, za petljanje po fajlu /etc/passwd)

sed

Sed ustvari ima više primena, ali njegova najjednostavnija upotreba je "zameni ovim stringom, gde vidiš onaj string". Sintaksa za ovo je

sed 's/staristring/novistring/'

Ova komanda će pratiti svaku liniju unosa i zameniće PRVO pojavljivanje "staristring"-a sa "novistring"-om.

Ako želite da zameni SVAKO pojavljivanje u posmatranoj liniji, morate koristiti 'global' modifikator na kraju komande:

sed 's/oldstring/newstring/g'

Ako želite da zamenite bilo staristring, bilo novistring, koji imaju kose crte u sebi, možete upotrebiti drugačiji karakter za odvajanje:

sed 's:/old/path:/new/path:'

awk

Awk zaista zaslužuje sopstveni tutorijal, pošto je, sam za sebe, mini programski jezik. I, on ga i ima!

Ali ako nemate vremena da prolazite kroz njegov tutorijal, AWK se najčešće koristi da prikaže na ekranu određene kolone nekog fajla. Možete navesti koji karakter razdvaja kolone. Podrazumevano je da je to prazan prostor ('whitespace': space ili TAB). Ali kanonički primer je: "Kako prikazujem na ekranu prvu i petu kolonu fajla sa lozinkama?".

awk -F: '{print $1,$5}' /etc/passwd

"-F:" definiše da "separator polja" bude ':'

Kratak kod između jednostrukih navodnika je mini program koji awk interpretira. Možete reći awk-u ime(na) fajl(ov)a, nakon što mu kažete koji program da pokrene. ILI ga možete koristiti u nekoj cevi, tj. pajpu.

Morate da koristite jednostruke navodnike za mini program, da bi izbegli da $1 bude proširen od samog shell-a. U ovom slučaju, želite da awk vidi bukvalno '$1'

"$x" znači 'x'-ta kolona
Zapeta je brz način da kažete “stavi razmak ovde”.
Ako ste, umesto toga, uradili ovo

awk -F: '{print $1 $5}' /etc/passwd

awk neće staviti nikakav razmak između kolona!

Ako ste zainteresovani da naučite višeo AWK-u, pročitajte moj AWK tutorijal


POČETAK tutorijala
Naredno poglavlje: Funkcije Prethodno poglavlje: Napredni operatori za rad sa promenljivama

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Ksh funkcije

Funkcije su ključne za pisanje gotovo SVAKOG programa koji je duži od jedne stranice teksta. U drugim jezicima funkcije mogu drugačije da se nazivaju. Ali, suštinski, sve je to stvar raščlanjivanja većeg programa u manje komade, kojima može da se upravlja. U idealnom slučaju, funkcije su nešto kao 'objekti' za tok programa. Odaberete deo vašeg programa koji je u priličnoj meri samostalan, i napravite od njega njegovu sopstvenu 'funkciju'.

Zašto su funkcije kritične?

Pravilno napisane funkcije mogu da egzistiraju same za sebe, i da utiču samo na manje stvari, izvan sebe. Trebalo bi da DOKUMENTUJETE koje to stvari, izvan sebe, funkcija menja. Onda možete vrlo pažljivo da proučite tu funkciju, i da utvrdite da li ona zaista radi ono što vi mislite da radi :-)

Kada vaš program ne radi kako treba (KADA, ne ako), tada u njegovom kodu možete sebi napraviti male “debug” beleške u sekciji otprilike za koju mislite da ne funkcioniše. Ako sumnjate da funkcija ne radi, tada, sve što treba da proverite je

Kada ste to uradili, onda znate da je celokupna funkcija ispravna, za taj konkretan ulaz (skup ulaza), i možete tražiti greške na drugom mestu.

Banalna funkcija

stampajporuku() {
    echo "Zdravo, ovo je funkcija stampajporuku"
}

stampajporuku

Prvi deo koda, od prvog "stampajporuku()" sve do krajnjeg '}', je definicija funkcije. Tu se samo definiše šta funkcija radi, kada odlučite da je pozovete. Ona ništa ne RADI, dok vi ustvari ne kažete "Želim sada da pozovem ovu funkciju".

U ksh-u pozivate funkciju ponašajući se kao da je ona regularna komanda, kako je pokazano gore. Samo stavite ime funkcije na početak vaše linije. Ili na bilo koje drugo mesto gde dolaze komande. Na primer,

echo Poruka je: `stampajporuku`

Zapamtite: Baš kao sopstvena, zasebna shell skripta. Što znači da, ako unutar funkcije pristupite promenljivoj "$1", to je prvi argument prosleđen funkciju, a ne shell skripti.

Otklanjanje grešaka u vašim funkcijama

Ako zaista imate ozbiljnih poteškoća, trebalo bi da bude lako da kopirate celu funkciju u drugi fajl, i da je testirate odvojeno od glavnog programa.

Ista vrsta modularnosti može se postići pravljenjem zasebnih skript fajlova, umesto funkcija. Na neki način, ovo skoro da je i poželjno, jer je tada lakše testirati svaki deo ponaosob. Ali funkcije se izvršavaju daleko brže od zasebnih shell skripti.

Fin način da započnete veliki projekat, je da krenete sa više zasebnih shell skripti, a da te skripte zatim “upakujete” u funkcije u vašoj glavnoj skripti, onda kada budete zadovoljni time kako rade.

KLJUČNO PITANJE: exit nasuprot return

Glavna promena, onda kada prelazite sa shell skripti na funkcije, je korišćenje komande "exit".

'exit' će izaći iz same skripte, bilo da se nalazi u funkciji, ili ne.
'return' će samo napustiti funkciju. Međutim, kao i 'exit', ova komanda može da vrati podrazumevanu “uspešno obavljeno” vrednost, 0, ili bilo koji drugi broj od 1-255, koji navedete. Zatim možete proveriti povratnu vrednost funkcije, na isti način kao što možete da proverite povratnu vrednost nekog spoljnog programa, pomoću promenljive $?.

# Ovo je samo glupa skripta. Ona ne RADI ništa

fatal(){
    echo FATALNA GREŠKA
    # Ovo će prekinuti funkciju 'fatal', kao i celu skriptu
    # u kojoj se ona nalazi!
    exit
}

lessthanfour(){
    if [[ "$1" = "" ]] ; then echo "hej, dajte mi neki argument" ; return 1; fi

    # ovde bi trebalo da koristimo 'else', ali ovo je samo demonstracija
    if [[ $1 -lt 4 ]] ; then
        echo Argument je manji od 4
        # ZAVRŠILI smo sa ovom funkcijom. Ona ne radi ništa više
        # ovde. Ali shell skripta će nastaviti sa radom nakon povratka pozivaoca
    fi

    echo Argument je jednak, ili VEĆI od 4
    echo Mogli bismo da radimo druge stvari, ako bismo želeli to sada
}

echo obratite pažnju na to da gornje funkcije nisu čak ni pozivane. One su samo
echo definisane

Ogoljen "return" u shell skripti je greška. Ova komanda se može upotrebiti unutar funkcije.

KLJUČNO PITANJE: "delokrug" za funkcijske promenljive!

Budite oprezni: Funkcije se ponašaju skoro isto kao eksterne skripte ... izuzev što su, po definiciji, sve promenljive DELJENE unutar istog ksh procesa! Ako unutar neke funkcije promenite vrednost određene promenljive … vrednost te promenljive će i dalje moći da bude promenjena nakon što napustite datu funkciju!! Pokrenite ovu skriptu da vidite na šta sam mislio.

#!/bin/sh
# Ponaša se isto sa /bin/sh, ili /bin/ksh, ili /bin/bash
subfunc(){
       echo sub: var je na početku $var
       var=2
       echo sub: var je sada $var
}
var=1
echo var je na početku $var, pre pozivanja funkcije '"subfunc"'
subfunc  # poziva našu funkciju
echo nakon izvršenja funkcije, var je sada $var

Da izbegnete ovakvo ponašanje, i date promenljivoj ono što je poznato kao "lokalni delokrug", možete upotrebiti komandu typeset, da definišete promenljivu kao lokalnu za datu funkciju.

#!/bin/ksh
# Morate za ovo da koristite neki savremeni sh poput /bin/ksh, ili /bin/bash
subfunc(){
    typeset var
       echo sub: var je na početku $var '(empty)'
       var=2
       echo sub: var je sada $var
}
var=1
echo var je na početku $var, pre pozivanja funkcije '"subfunc"'
subfunc  # poziva našu funkciju
echo nakon izvršenja funkcije, var je sada $var

Drugi izuzetak od ovoga je ako pozovete neku funkciju da se izvršava u 'pozadini', ili kao deo neke cevi-pajpa (poput

echo val | function
)
Ovim će funkcija da bude pozvana u zaseban khs proces, koji ne može da dinamički deli promenljive unazad sa svojim roditeljskim shell-om. Još jedan način da se ovo desi je ako koristite kontra navodnike (backticks) da pozovete datu funkciju. Ovako se funkcija tretira kao da je pozvana spolja, i pravi račvanje (fork) na novi shell. To znači da promenljiva iz roditeljskog procesa neće biti ažurirana. Npr:

func() {
       newval=$(($1 + 1))
       echo $newval
       echo in func: newval završava kao $newval
}
newval=1
echo newval je u glavnom programu $newval
output=`func $newval`
func $newval
echo izlaz je : $output
echo newval u glavnom programu završava kao $newval

Pišite komentare!

Na posletku, kao što sam pomenuo u poglavlju o dobroj praksi, nemojte zaboraviti da komentarišete vaše funkcije! Mada su shell skripte generalno lakše za čitanje od većine programskih jezika, pravi ljudski jezik je neprevaziđen za objašnjavanje toga šta neka funkcija radi!


POČETAK tutorijala
Naredno poglavlje: Ugrađene funkcije Prethodno poglavlje: POSIX.1 alati

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Ksh ugrađene funkcije

Pozivanje mnogih UNIX programa u /bin i drugde može biti veoma korisno. Jedan nedostatak je brzina. Svaki put kada pozovete poseban program, to dosta opterećuje sistem dok se program startuje. Pa zato programeri koji su svesni ovoga pokušavaju da koriste ugrađene funkcije pre nego spoljne. U konkretnom slučaju, ksh programeri bi trebalo da uvek pokušavaju da koriste '[[ ]]' pre nego '[ ]', osim tamo gde je [] neophodno.

Funkcije u ksh-u, koje su po meni korisnije, su:

  1. 'read' i 'set' funkcije
  2. ugrađeni 'test': [[ ]]
    (Ali ovo očigledno NIJE deo POSIX-a!!)
  3. ugrađena matematika : $(( ))
  4. ugrađeni prelom teksta (typeset)

Pogledajte strane sa uputstvima za 'test' i 'typeset', ako hoćete celokupne informacije o ovim zverima.

Read i Set

read varname

će podesiti promenljivu varname da ima vrednost sledećeg očitavanja iz standardnog ulaza.

Ono šta obično sledi, je

set $varname

Ova komanda podešava argument promenljive $1, $2, itd. na vrednosti kao da je program bio pozvan pomoću $varname kao string argumenta prosleđenog shell skripti. Tako da, ako je vrednost promenljive varname "prvi drugi treći", onda je $1="prvi", $2="drugi", i $3="treći".

Imajte na umu da ako želite da pristupite “dvo-cifarnim” argumentima, ne možete koristiti promenljivu "$10". Ona će biti interpretirana kao "$1,""0". Da pristupite argumentu pod rednim brojem 10, i višem, morate eksplicitno da definišete granice oznake te promenljive, pomoću velikih zagrada:

echo ${10}

To je takođe dobro znati i ako želite da odmah iza promenljive sledi neki string. Uporedite izlaz sledećih linija:

a="A "
echo $astring
echo ${a}string

Funkcija test

Ukratko, funkcija 'test' vam može dati da proverite status fajlova ILI znakovnih vrednosti (stringova).
Evo njenih najčešćih upotreba.

if [[ $? -ne 0 ]] ; then echo status je loš ; fi
if [[ "$var" != "good" ]] ; then echo var nije dobra ; fi
if [[ ! -f /file/name ]] ; then echo /file/name se ne nalazi tamo ; fi
if [[ ! -d /dir/name ]] ; then echo /dir/name nije direktorijum ; fi

Molim vas, imajte u vidu da je [[]] specijalna ugrađena verzija testiranja, koja je skoro, ali ne i 100%, slična standardnom []. Glavna razlika je ta što proširenje pomoću “džoker znakova” (wildcard expansion) ne funkcioniše unutar [[]].

Ugrađena matematika

Matematički analizator (math evaluator) je veoma koristan. Sve što se nađe unutar duplih zagrada biva analizirano pomoću osnovnih matematičkih funkcija. Na primer;

cetiri=$((2 + 2))
osam=$(($four + 4))
print $(($cetiri * $osam))
# Unutar (()), znaci $ su opcioni, tako da sledeće funkcioniše...
# ali možda biste želeli da ih zadržite iz određenih razloga..
print $((cetiri * osam))

# čak i konverzija heksadecimalnih u dekadne brojeve
print $((0xff))

Ovo nije matematika, ali je ugrađen metod da se na drugi način od dekadnih vrednosti dođe do heksadecimalnih:

printf "%x\n" 255    # ovo izbacuje "ff"
printf "%.4x\n" 255  # ili, ako vam je potreban broj sa fiksnom širinom polja, koristite ovo

Upozorenje: Neke verzije ksh-a dozvoljavaju da se koristi pokretan zarez sa $(()). Većina to NE DOZVOLJAVA

Ograničenja ugrađenih funkcija

Budite oprezni sa pretpostavkama. Budući da "ugrađeno" nije uvek brže od eksternog programa, ako je neka operacija složena. Na primer, nema puno smisla napisati neki čisto shell ekvivalent banalnog korišćenja funkcije awk, "awk '{print $2}'", za prikazivanje druge kolone. Međutim, uporedite ih na nekom dugačkom fajlu:

# funkcija koja podražava komandu awk '{print $2}'
sh_awk(){
    while read jedan dva tri ; do
    print $dva
    done
}

# a sada, uporedite brzine ova dva metoda

time sh_awk /dev/null
time awk '{print $2}' /dev/null

awk verzija biće mnogo, mnogo brža. To je zato što se ksh skripte interpretiraju, svaki put kada se izvrši neka linija. AWK, međutim, učitava svoj program u jednom prolazu, i zaključuje šta radi JEDANPUT. Jednom kada se to opterećenje stavi na stranu, on onda može da ponavlja svoje instrukcije veoma brzo.


POČETAK tutorijala
Naredno poglavlje: Preusmeravanje i cevi Prethodno poglavlje: Funkcije

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Preusmeravanje i cevi (pajpovi)

Postoji mnogo čudnih i interesantnih načina da se zajedno povežu alatke. Većinu ovih načina ste verovatno već videli.

Standardno preusmeravanje ka fajlu;

ls > /tmp/listing

i odvođenje izlaza jedne komande ka drugoj

ls | wc -l

Ali bourne-shell-ovi derivati daju vam još veću moć od toga.

Većina pravilno napisanih programa daje izlaze na jedan od dva načina.

  1. Poruke o napredovanju procesa idu u stdout, poruke o greškama idu u stderr
  2. Podaci idu u stdout, poruke o progresu I o greškama idu u stderr

Ako znate u koju kategoriju spada vaš alat, možete raditi interesantne stvari.

Preusmeravanje

Jedan program, neuobičajen za korišćenje u ovom primeru, je program "fuser" koji radi pod solaris-om. On vam daje dugačak spisak procesa koji koriste neki određeni fajl. Na primer:

$ fuser /bin/sh
/bin/sh:    13067tm   21262tm

Ukoliko ste želeli da vidite samo procese koji koriste taj fajl, možda ćete u početku uzdisati i pitati se kako na najbolji način da analizirate spisak koristeći awk, ili šta već. Međutim, fuser ustvari već deli podatke za vas. On stavlja stvari koje vas možda neće zanimati u stderr, a mesnate “podatke” u stdout. Tako da, ako odbacite stderr, sa '2>' specijalnim preusmeravanjem, dobijate

$ fuser /bin/sh  2>/dev/null
   13067   21262

što je onda trivijalno upotrebljivo.

Na žalost, nisu svi programi tako jasni :-) Ipak, dobro je biti svestan ovih stvari, a takođe i vraćanja statusa. Komanda 'grep' ustvari vraća status na osnovu toga da li je našla liniju. Status poslednje komande je pohranjen u promenljivoj '$?'. Pa ako je sve što vas zanima to “da li je fajl 'biggles' u direktorijumu /etc/hosts?" možete uraditi sledeće:

grep biggles /etc/hosts >/dev/null
if [[ $? -eq 0 ]] ; then
    echo YES
else
    echo NO
fi

Kao i obično, ima dosta drugih načina da se izvrši ovaj zadatak, uključujući čak i korišćenje iste 'grep' komande. Međutim, ovaj metod ima tu prednost što ne traći cikluse operativnog sistema sa privremenim (temp) fajlom, niti rasipa memoriju sa potencijalno vrlo dugačkom promenljivom.
(Ukoliko ste tražili nešto što bi potencijalno moglo da se podudara sa stotinama linija koda, tada var=`grep something /file/name` može postati veoma dugačko).

Preusmeravanje u okviru linije (inlajn)

Videli ste preusmeravanje na fajl. Ali takođe možete preusmeriti ulaz od fajla. Za programe koji mogu da uzimaju podatke u stdin-u, ovo je korisno. Komanda 'wc' može uzeti ime fajla kao argument, ili može koristiti stdin. Tako sve komande koje slede daju, grubo uzev, isti rezultat, mada se u njihovoj unutrašnjosti dešavaju različite stvari:

wc -l /etc/hosts
wc -l < /etc/hosts
cat /etc/hosts | wc -l

Dodatno, ako ima nekih fiksnih linija koje želite da koristite, i ne želite da se maltretirate praveći privremeni fajl, možete se ponašati kao da je deo vaše skripte poseban fajl!. Ovo se radi pomoću specijalnog operatora za preusmeravanje, '<<'.

command << EOF

znači, "izvršavaj ‘komandu’, ali tako da njen stdin dolazi od ovog fajla ovde, sve dok ne vidiš oznaku 'EOF'"

EOF je tradicionalna oznaka. Ali vi ustvari možete koristiti koju god želite jedinstvenu oznaku. Uz to, možete koristiti i proširenje promenljivih u ovoj sekciji!

DATE=`date`
HOST=`uname -n`
mailx -s 'dugačko upozorenje' root << EOF
Nešto je krenulo strašno loše sa sistemom $HOST
at $DATE
EOF

Cevi (pajpovi)

Za slučaj da ste propustili ovo ranije, cevi uzimaju izlaz iz jedne komande i stavljaju ga na ulaz druge komande. Ove komande zapravo možete staviti i zajedno, kao što se vidi ovde;

grep hostspec /etc/hosts| awk '{print $1}' | fgrep '^10.1.' | wc -l

To je prilično lak način da se otkrije koji ulazi u /etc/hosts imaju ujedno i određeni tekstualni obrazac u svom imenu, I IP adrese koje pripadaju određenom opsegu.

“Nedostatak” ovog načina je što je vrlo rasipnički. Svaki put kada koristite više od jedne cevi odjednom, treba da se zapitate da li postoji bolji način da uradite to što radite. A za ovaj slučaj svakako važi da, sasvim sigurno POSTOJI bolji način:

grep '^10\.1\..*hostspec' /etc/hosts | wc -l

Ustvari postoji način da ovo uradite jednom jedinom awk komandom. Ali ovo nije lekcija kako da koristite AWK!

Kombinovanje cevi i preusmeravanja

Interesantan primer kombinovanja cevi sa stdin/err i sa preusmeravanjem, je komanda "tar". Ako upotrebite komandu "tar cvf file.tar dirname", ona će kreirati tar fajl, i prikazati na ekranu imena svih fajlova iz direktorijuma dirname, koji se stavlja u tar fajl. Takođe je moguće uzeti iste 'tar' podatke, i izbaciti ih u stdout. Ovo je korisno ako želite da komprimujete podatke, u isto vreme dok arhivirate:

tar cf - dirname | compress > file.tar.Z

Ali važno je imati u vidu da cevi, po definiciji, uzimaju podatke samo na stdout-u! Pa je zato moguće dobiti interaktivni uvid u proces, koristeći

tar cvf - dirname | compress > file.tar.Z

stdout je preusmeren na određenu cev, ali stderr se i dalje prikazuje vašem terminalu, tako ćete dobiti fajl-po-fajl izveštaj o napredovanju. Ili, naravno, možete da ga preusmerite negde drugde, sa komandom

tar cvf - dirname 2>/tmp/tarfile.list | compress > file.tar.Z

Indirektno preusmeravanje (“inlajn” fajlovi)

Dodatno, postoji i specijalan tip cevi+preusmeravanja. Ovo funkcioniše samo na sistemima sa /dev/fd/X podrškom. Možete automatski da generišete neki “lažan” fajl kao rezultat komande koja obično ne generiše fajlove. Imena lažnih fajlova biće tipa /dev/fd/{ovdedolazinekibroj}

Evo jednog primera koji ne radi ništa korisno

wc -l <(echo jedna linija) <(echo još jedna linija)

wc će izvestiti da je uočio dva fajla, "/dev/fd/4", i "/dev/fd/5", i da svaki "fajl" sadrži po 1 liniju. Iz svoje sopstvene perspektive, wc je bio pozvan jednostavno kao

wc -l /dev/fd/4 /dev/fd/5

Postoje dve korisne komponente ovoga:

  1. Možete obraditi izlaz VIŠE komandi odjednom
  2. To je brz-i-pokvaren način da kreirate cev iz komande koja “zahteva” ime fajla (sve dotle dok ona obrađuje svoj ulaz samo u jednostrukom neprekidnomtoku podataka).

POČETAK tutorijala
Naredno poglavlje: Interesantne stvarčice Prethodno poglavlje: Ugrađene funkcije

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Ostale stvarčice

A evo stvari koje nisam mogao da uklopim ni na jedno drugo mesto :-)

  1. eval
  2. Backtick-ovi
  3. Pozicioniranje teksta/boja/curses stvari
  4. Meniji bazirani na brojevima
  5. Sirovi TCP pristup
  6. Grafika i ksh

eval

Komanda eval je način da tražite da nešto unesete direktno. Ovo je veoma opasna komanda. Pažljivo razmislite pre nego je upotrebite.

Jedan način korišćenja eval-a, je da se koristi spoljna komanda za podešavanje promenljivih kojima unapred ne znate ime. Ili GRUPE promenljivih. Uobičajeno korišćenje ovoga je da se podese promenljive terminalne veličine nakon logovanja:

eval `resize`

Backtick-ovi

Postoje načini da se izlaz iz jedne komande stavi kao komandna linija druge. Ima dva metoda da se ovo uradi, i oni su u suštini isti:

echo Ovo je uptime: `uptime`
echo Ovo je uptime: $(uptime)

Tehnički, drugi je taj koji je poželjniji po POSIX-u.

Uz kreiranje dinamičkog izlaza, ovo je takođe veoma korisno za podešavanje promenljivih:

datestring=`date`
echo "Trenutni datum je: $datestring"

Pozicioniranje teksta/igre sa bojama

Ovo je ustvari obimna tema i skoro da zavređuje poseban, sopstveni turorijal. Ali ja nameravam samo ukratko da je pomenem.

Nekim ljudima je možda bliska "curses" biblioteka. To je način da se manipuliše tekstom i da se on pomera po ekranu, nezavisno od toga koju vrstu “terminala” korisnik upotrebljava.

Kako je već rečeno, ovo je potencijalno obimna tema. Tako da ću vam samo dati banalan primer, i zatim reći “Idite da pročitate stranu sa uputstvom za tput”. Pa dobro, ustvari, treba da pročitate uputstvo za “tput”, I UJEDNO da pročitate uputstvo za"terminfo" ili za "termcap", da biste shvatili koje magično ime od 3-5 slova treba da koristite. Na primer, ta uputstva bi trebalo da vam kažu da je "cup" skraćenica za komandu "cursor_address". Ali sa tput-om morate koristiti “cup” A NE “cursor_address".

tput init
tput clear
tput cup 3 2
print -n "Evo čistog ekrana, sa ovim rečima blizu vrha"
endline=`tput cols`
tput cup $(($endline - 2))
print "a sad, nazad k’ vama"
sleep 2

Gornji primer briše ekran, prikazuje dati red teksta na ODREĐENOM mestu na ekranu, a zatim za vas vraća kursor dole, blizu dna ekrana.

PS: Ukoliko ste se puno igrali stavljanjem stvari po ekranu, možda ćete želeti da upotrebite

tput reset

kao poslednju stvar pre nego se vaša shell skrita završi.

Meniji bazirani na brojevima

Ne morate da pravite svoju sopstvenu “izaberi broj” funkciju: ksh već ima jednu! Ali imajte na umu da ona vraća vrednost linije, a ne broj linije.

select word in jedan dva tri izlaz; do
    echo word is $word
    echo reply is $REPLY
    if [[ "$word" = "izlaz" ]] ; then
        break;
    fi
done

Ovaj program će prikazati mini meni, poput sledećeg:

1) jedan
2) dva
3) tri
4) izlaz
#?

Upamtite da će se program vrteti između "do ... done" dok na neki način ne izazovete prekid! (ili dok korisnik ne pritisne control-c's ili bilo štadrugo). Zato ne zaboravite izlazni uslov!

Sirovi TCP pristup

Ksh88 ima ugrađeni virtuelni filesystem koji izgleda kao da je pod /dev/tcp. Možete ga koristiti da pravite konekcije na određene portove, ako znate IP adrese.

Evo banalnog primera koji samo otvara konekciju na SMTP server. Imajte u vidu da je konekcija polu-duplex: Vi NE vidite podatke koje šaljete drugoj strani.

#!/bin/ksh -p

MAILHOST=127.0.0.1
exec 3<>/dev/tcp/$MAILHOST/25 || exit 1

read -r BANNER <&3
echo BANNER is $BANNER
print -u3 HELO myhost.com
read -r REPLY <&3
echo REPLY is $REPLY

Izlaz će izgledati otprilike kao sledeći:

BANNER is 220 yourhost.domain.com ESMTP Sendmail 8.11.6+Sun/8.11.6; Tue, 3 Dec 2002 17:30:01 -0800 (PST)
REPLY is 250 yourhost.domain.com Hello localhost [127.0.0.1], pleased to meet you

Zapamtite da koristimo "-r" oznaku za čitanje. U ovom konkretnom primeru, to nije neophodno. Ali u opštem slučaju, ovo će vam dati “sveže” podatke. Vodite računa o tome da će shell, ako ne može da otvori navedeni port, automatski ubiti celu vašu skriptu, sa statusom 1.

Takođe možete odbaciti preostale podatke koji čekaju na slanje, kad god želite, izvršavajući komandu

cat <&3 >somefile

Grafika i ksh

Toga nije svesno mnogo ljudi, ali ustvari postoji grafička verzija ksh-a, nazvana “dtksh”. Napravljena je kao deo “CDE”-a. Bilo koji od modernih UNIX-a bi trebalo da dolazi sa ovom verzijom, u direktorijumu /usr/dt/bin/dtksh. Ako ste zainteresovani, pogledajte neke dtksh demoe koje je napisao neko drugi. I/ili možete pogledati da li na vašem računaru postoji direktorijum /usr/dt/share/examples/dtksh/.


POČETAK tutorijala
Naredno poglavlje: Paranoja i dobro programiranje: Budite dobar programer! Prethodno poglavlje: Preusmeravanje i cevi

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Paranoja i dobra programerska praksa

Prvo, malo dobre programerske prakse:

Komentarišite svoj kod.

Zaista bi trebalo da imate NAJMANJE poneki komentar za svaku stranu (što će reći za svake 24 linije koda).
Idealno bi bilo da uvek komentarišete sve vaše funkcije. Funkcije u jednom redu verovatno mogu stajati same, ali u drugim slučajevima, brzi komentar u jednom redu je stvar koju je dobro imati za male funkcije.

# Ova funkcija čisti fajl pre štampanja
pcleanup(){
    ....
}

Za duže funkcije zaista bi trebalo da primenjujete specifikaciju u obliku formalnog komentara. Nešto poput

# Funkcija xyz
#  Upotreba: xyz arg1 arg2 arg3 arg4
#    arg1 je uređaj
#    arg2 je fajl
#    arg3 je koliko žarko želite da ga komadate
#    arg4 je neki opcioni izlazni fajl
#  Rezultat: fajl će biti prenet uređaju, uz
#    odgovarajuće i/o kontrole (ioctls). Svaka poruka o grešci biće snimljena u izlazni
#    fajl, ili, u drugom slučaju, u stderr
xyz(){
    ...
}

Imajte na umu da su shell skripte, same po sebi, jedna velika “funkcija”. Zato ne zaboravite osnovne komentare o funkcionalnosti vaše shell skripte, na vrhu fajla!

UVUCITE RED!

Svaki put kada započnete funkciju, uvucite red.

Svaki put kada ste u nekoj while petlji, ili if klauzuli, uvucite red.

Ovo olakšava da se na prvi pogled vidi na kom se nivou nalazite.

# najviši nivo
print ovo je vrh

somefunction(){
    # uvučeni redovi u funkcijama
    print sada smo u funkciji
   
    if [[ "$1" != "" ] ; then
        # da, JOŠ JEDNO uvlačenje reda!
        print "Hej, imamo argument: $1"
        print puni argumenti su $*
    else
        # opet uvučen red!!
        print "Pa dobro. Nema argumenata za igranje"
    fi

    print ostavljamo somefunction sada
}

# I sada jasno možemo videti da je sve ovo izvan bilo koje funkcije.
# Ovo olakšava nalaženje "glavne linije" date skripte
print originalni argumenti shell skripte su $0
print hajde da isprobamo somefunction
somefunction evo nekih argumenata

Traženje grešaka

Ukoliko koristite skripte za proveru važnih sistema, ili za izvršavanje ključnih funkcija, veoma je važno obezbediti povratne informacije pozivajućem procesu, onda kada i ako nešto krene kako ne treba.

Najjednostavniji način da se ovo uradi, je prosto

  exit 1
  # (ali bilo bi lepo da se napiše NEKA poruka pre izlaženja iz programa!)

Dobri programi će primetiti da je vaša skripta izašla sa statusom koji je različit od nule. [Sećate se, status poslednje komande je u '$?']
U idealnom slučaju, oni će se žaliti.
Sa druge strane, nekada su vaše skripte te koje vrše pozivanje!

U takvoj situaciji, može biti zgodno da se ima jedna skripta najvišeg nivoa koja pazi na stvari. Jednostavan primer je:

fatal(){
    # Nešto je krenulo užasno loše.
    # odštampaj errormessage ukoliko je ima, zatim izađi sa
    # statusom greške

    if [[ "$1" != "" ]] ; then
        print Nešto je krenulo užasno loše sa "$1"
    else
        print "nešto je krenulo užasno loše (Negde?)"
    fi

    # Mogli biste takođe da želite da POŠALJETE EMAIL, ili da aktivirate PEJDŽER ili
    # nešto ovako:
    # mailx -s "Arrrg! Omanuli smo sa proverama!" admin@yourhost.com < /dev/null
    #
    exit 1
}

check_on_modems
if [[ $? -ne 0 ]] ; then     fatal modems ; fi

check_on_network
if [[ $? -ne 0 ]] ; then    fatal network ; fi

check_on_servers
if [[ $? -ne 0 ]] ; then     fatal servers ; fi

Zapamtite da čak i moja paranoična funkcija 'fatal', JESTE PARANOIČNA!

Pretpostavlja se da ćete, u normalnim slučajevima, da je pozivate sa "fatal šta-je-omanulo". Ali ukoliko iz nekog razloga ne bude tako, ona će to primetiti i obezbediti “default”-ni argument.

Ponekad, pretpostavljanje da $1 sadrži validne podatke, može potpuno upropastiti ostatak vaše funkcije ili skripte. Tako da, ako je to neka važna funkcija, nemojte pretpostavljati ništa! Ovo naročito važi kod CGI scripti. [Uzdah]. Da, Virginia, JESTE moguće pisati CGI u nečemu što nije perl.


cron job paranoja

Ukoliko pišete skriptu koja je posebno za cronjob, postoje dve stvari kojih treba biti svestan. Prva najvažnija stvar je;

Podesite svoju PATH promenljivu!!!

Ljudi ovo uvek zaboravljaju. Nije važno šta se nalazi u vašem fajlu .profile, cron će resetovati promenljivu PATH na nešto stvarno kratko i glupo, kao na primer samo na /usr/bin. Zato eksplicitno podesite promenljivu PATH=/whatever:/usr/bin explicitly u vašim cron skriptama.

Druga stvar je više jedna savetodavna napomena.

cron, po “default”-u snima sve što se pošalje u 'stderr', i to ŠALJE E-MAILOM vlasniku cron job-a. Pa, nekada, ako prosto želite da neka mala greška bude negde prijavljena, dovoljno je da samo unesete komandu

print "Hej, ovo je nekako uvrnuto" >/dev/fd/2

što će poslati izlaz sa funkcije print u stderr, koji će dalje otići e-mailom. Drugi način da se to uradi, ako vaš sistem nema /dev/fd, može biti

print "Vau, ovo je izmučeno" 1>&2

Suprotno, ako želite da odbacite SAV izlaz, koristite

command >/dev/null 2>&1

Ukoliko ne čitate redovno e-mailove za posmatranog korisnika , možete ili podesiti nadimak (alijas) za tog korisnika, da bi prosleđivali sve njegove e-mailove vama, ili uraditi ovo

export MAILTO=my@address.here

Međutim, MAILTO trik ne funkcioniše kod svih cron demona.


POČETAK tutorijala
Naredno poglavlje: Stvaran kod: Jedan koristan program, urađen na pogrešan, pa zatim na ispravan način. Prethodno poglavlje: Interesantne stvarčice

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Primer razvoja skripte

Dobar, loš, i ružan

Nadamo se da ste pročitali sva druga poglavlja do ovde. Ova strana će vam dati širi uvid u pisanje shell skripti.

Evo četiri verzije suštinski istog programa: omotača za menjanje nekog fajla pod kontrolom verzija od strane SCCS-a.
Osnovni zadatak je da se upotrebi sccs komanda da se “proveri” fajl koji je pod kontrolom verzija, a zatim da se taj fajl automatski izmeni. Nakon toga, skripta će se koristiti od strane “korisnika”, tzv. programera, koji možda nisu naročito napredni UNIX korisnici. Otud potreba za skriptom-omotačem.

Dok je osnovna funkcionalnost ista u svim verzijama, razlike po pitanju bezbednosti i upotrebljivosti između prve i poslednje verzije su zapanjujuće.

Prva verzija je krajnje loša: bila bi napisana od strane nekoga ko je upravo nabavio knjigu o shell skriptovanju, i ko je odlučan: “ja sam sada programer”.

Druga je izvesno poboljšanje, jer pokazuje određenu brigu o korisnicima, imajući bezbednosne provere.

Treća je već dobra, solidna verzija. Ona je dobar model za vaše skripte.

Poslednja skripta je program “u punom cvetu”, paranoidan, komentarisan sam po sebi, sa ekspertskim-eksplozivnim svojstvima. Ovo je način na koji bi ga napisao profesionalni programer. Nemojte da vas ovo obeshrabri: to je način na koji i vi možete i treba da pišete programe! Možete početi sa verzijom sličnom onoj prvoj, glupoj, kao prvim korakom u vašem razvoju koda, čisto da obezbedite da imate osnovnu funkcionalnost za vaš zadatak. Ali nakon što se pokaže da vaš kod funkcioniše, treba odmah da ga unapredite u neku razumniju verziju.

Napomena: ovde se nalazi pregled dobre prakse, prikazan na dnu ove stranice.


Verzija programera početnika

#!/bin/ksh

sccs edit $1
if [ "$EDITOR" = "" ] ; then
    EDITOR=vi
fi
$EDITOR $1

U ovoj verziji postoji izvestan pokušaj da program bude “user friendly”, time što se proverava da li ima podešenja EDITOR-a od strane korisnika, i što se ta podešenja koriste, ako su dostupna. Međutim, ne postoje komentari, nema provere grešaka, i uopšte nema pomoći korisniku!


Verzija sistem administratora koji još uči posao

#!/bin/ksh

# Autor: Joe Newguy

if [ $# -lt 1 ] ; then
    print "Ovaj program će proveriti fajl, ili fajlove, pomoću sccs"
    exit 1
fi

# podešava EDITOR promenljivu na vrednost "vi" ukoliko nije već podešena
EDITOR=${EDITOR:-vi}

sccs edit $@
$EDITOR $@

Ovo je izvestan pomak u odnosu na prethodnu verziju. Ova verzija prihvata više fajlova kao potencijalne argumente. Uvek je lepo biti fleksibilan oko broja fajlova koje može da obradi vaša skripta. Ona takođe ima poruku o načinu korišćenja, ako se skripta pozove bez argumenata. Uz to, uvek je dobra ideja da stavite svoje ime u kod, osim ako radite sami za sebe (za kompaniju "Me, Myself and I, Inc.").

Na žalost, još uvek ponešto nedostaje, kao što ćete moći da vidite kada uporedite ovu verziju sa sledećom.


Verzija iskusnog administratora

#!/bin/ksh

# Omotač za SCCS izmene, verzija 0.3
#  Autor - Sistem administrator
#  Upotreba: pogledajte usage() funkciju, dole

usage(){
    print sedit - omotač za izmenu fajlova pod SCCS
    print "uotreba: sedit file {file2 ...}"
}

# Dodeljuje promenljivoj EDITOR vrednost "vi" ako joj nije dodeljena druga vrednost
EDITOR=${EDITOR:-vi}
# Možda je veći u putanji, ali ne smeta da se doda još jednom.
# Izvinite, ja polazim od toga da su solaris mašine svuda: prilagodite po potrebi,
# ako se var scc nalazi negde drugde
SCCSBIN=/usr/ccs/bin
if [ ! -x $SCCSBIN/sccs ] ; then
    print ERROR: sccs nije instaliran na ovom računaru. Nije moguće nastaviti.
    usage
    exit 1
fi
PATH=$SCCSBIN:$PATH

if [ $# -lt 1 ] ; then
    usage
    print ERROR: nije naveden ni jedan fajl
    exit 1
fi

# Da, mogao bih koristiti "sccs edit $@" i potražiti pojedinačnu grešku, ali ovaj
# pristup omogućava bolje izveštavanje o greškama
for f in $@ ; do
    sccs edit $f
    if [ $? -ne 0 ] ; then
        print ERROR proveravanje fajla $f
        if [ "$filelist" != "" ] ; then
            print "Provereni su $filelist"
        fi
        exit 1
    fi
    filelist="$filelist $f"
done

$EDITOR $filelist
if [ $? -eq 0 ] ; then
    print ERROR: $EDITOR je vratio status greške
    exit 1
fi

Ovaj momak je u poslu već neko vreme. On je odgovorni sistem administrator, koji voli da bude pripremljen za nesreće. U ovom slučaju, najverovatnija “nesreća” je 100 poziva od programera koji pitaju “Zašto ovo ne radi kod mene?”. Tako da, kada se stvari pokvare, dobra ideja je da se korisniku pruži što je moguće više informacija.

Dobre stvari koje treba primetiti:

Uporedite prvu verziju programa sa ovom. Zatim probajte da napravite svoje skripte tako da budu više nalik ovoj!


Verzija iskusnog sistemskog programera

#!/bin/ksh

# Omotač za SCCS izmene, verzija 1.3
#  Autor - Phil Brown
#  Upotreba: pogledajte usage() funkciju, ispod

usage(){
    print sedit - omotač za izmene fajlova pod SCCS-om
    print "Upotreba: sedit [-c|-C] [-f] file {file2 ...}"
print "  -c  provera fajl(ov)a nakon završenih izmena"
    print "  -C  provera svih fajlova sa jednom revizionom porukom"
    print "  -f   ignorisanje grešaka tokom provere"
}

# Dodeljuje promenljivoj EDITOR vrednost "vi" ako nije dodeljena druga vrednost
EDITOR=${EDITOR:-vi}
    # Možda je veći u putanji, ali ne smeta da se doda još jednom.
# Izvinite, ja polazim od toga da su solaris mašine svuda: prilagodite po potrebi.
PATH=$PATH:/usr/ccs/bin
if [ ! -x /usr/ccs/bin/sccs ] ; then
    print ERROR: sccs nije instaliran na ovom računaru. Nije moguće nastaviti.
    usage
    exit 1
fi


while getopts "cCfh" arg
do
    case $arg in
        c)
            checkin="yes"
        ;;
        C)
            checkinall="yes"
        ;;
        f)
            force="yes"
        ;;
        h|*)
            usage
        exit 1
        ;;
    esac
done

shift $(($OPTIND - 1))

if [ $# -lt 1 ] ; then
    usage
print ERROR: nije naveden ni jedan fajl
    exit 1
fi

if [ "$checkinall" != "" ] && [ "$checkin" != "" ] ; then
    print WARNING: -c i -C upotrebljeni. Biće korišćen -C.
fi

# Da, mogao bih koristiti "sccs edit $@" i potražiti pojedinačnu grešku, ali ovaj
# pristup omogućava bolje izveštavanje o greškama.
#  "$@" je specijalan konstrukt koji pronalazi razmake u nazivima fajlova.
#   Imajte u vidu da "$*" NIJE 100% ista stvar.
for f in "$@" ; do
    sccs edit "$f"
    if [ $? -ne 0 ] ; then
        print ERROR proveravanje fajla $f
        if [ "$force" = "" ] ; then
            if [ "$filelist" != "" ] ; then
                print "Provereni su $filelist"
            fi
            exit 1
        fi
        # else, -f je na snazi. Nastavlja se dalje
    fi
    filelist="$filelist $f"
done

# Voleo bih da upotrebim "$filelist", ali to neće sačuvati razmake
# u nazivima fajlova
$EDITOR "$@"
if [ $? -eq 0 ] ; then
    print ERROR: $EDITOR je vratio status greške
    exit 1
fi

if [ "$checkinall" != "" ] ; then
    # -C opcija je upotrebljena. ponovo proveriti sve fajlove odjednom.
    sccs delget $filelist
    if [ $? -ne 0 ] ; then
        print "ERROR proveravati fajlove?"

Ovaj momak je u poslu već neko vreme. Đavola, on je pomogao da se NAPRAVI ovaj posao ;-)

Ovo je u originalu bila moja treća i konačna verzija. To je način kako bih ja stvarno napisao ovu skriptu. Ali, pomislio sam da bi ovo moglo biti donekle obeshrabrujuće za početnike u pisanju skripti, tako da sam napravio novi među korak, koji je gore prikazan.

Dodato u odnosu na prethodnu verziju:


Pregled pozitivnih svojstava

Evo pregleda svih pozitivnih svojstava dodatih kroz različite verzije.


POČETAK tutorijala
Naredno poglavlje: Ksh programiranje "na veliko" Prethodno poglavlje: Paranoja i dobro programiranje

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a


Programiranje na veliko

Ovo je relativno nova sekcija, inspirisana novom tehnikom koju isprobavam. Ova sekcija je za programera koji je sada već vrlo komforan sa ksh programiranjem i želeo bi da napravi neki kompleksan program.

Pored toga što programiranje na veliko čine izvodljivim, tehnike opisane na ovoj strani takođe i omogućavaju održavanje programa u dužem periodu.
Kada pišete neki važan program, i znate da će biti korišćen više godina, zaista je dobra ideja da ga pišete na takav način da bude lako izvodljivo otklanjanje grešaka u njemu, njegovo testiranje i modifikovanje, neku godinu kasnije, kada već budete zaboravili veći deo njegove unutrašnje logike.

Shell-skripting za velike zadatke???

Neki ljudi vole da pišu velike shell skripte u perl-u: međutim, pogrešno je birati jezik samo na osnovu veličine zadatka. Perl je dobar izbor za zadatke koji obuhvataju suptilno “igranje” sa podacima, bez pozivanja eksternih programa.
Suprotno od toga, Korn shell (a verovatno i drugi srodni shell-ovi, kao što je bash) je dobar izbor za zadatke sa izraženim "user command" tokom (česte komande i interakcije korisnika sa programom), gde dosta puta pozivate eksterne programe.

Ako uvidite da treba da obavite veliku količinu posla, sama veličina posla nije razlog da pređete na drugi programski jezik. Ona jeste, međutim, razlog da počnete sa drastično drugačijim razmišljanjem.

Najkorisniji način razmišljanja je onaj koji ima profesionalac, programer u nekom tradicionalnom programskom jeziku, koji će podeliti program u odvojene module.
Pošto je ovakvo razmišljanje tema nekih kurseva koji traju po ceo semestar, ja neću moći pošteno da ga obradim na jednoj jedinoj strani! Ipak, mogu makar da opišem osnovni okvir po kome možete vežbati ovakav način razmišljanja, u granicama ksh programiranja.

Kontrola izvornog koda

Pre svega, ako ćete pisati hiljade linija koda, možda je za vas vreme da razmislite o korišćenju neke vrste sistema za kontrolu izvornog koda/verzija (Source Code/Version Control system). Neću da gubim vreme tvrdeći kako postoji jedan takav, koji je najbolji; koristite koji god vam odgovara. Bilo koji (RCS, SCCS, CVS, git, subversion, mercurial, ??) može biti odgovarajući. Važno je da se odluči, ne toliko koji će se koristiti, već da li uopšte koristiti neki takav sistem.

Ako ništa drugo, kontrola verzija se nekad pokaže kao korisna, onda kada želite da pravite “izdanja” softvera.
Ovakav sistem takođe može biti pogodan za pronalaženje glupih jednolinijskih grešaka, koje su se iznenada promenile od poslednjeg snimanja.

Na kraju, može vam biti zaštita od slučajnog "rm somespec_ *.ksh" (obratite pažnju na nepredviđeni razmak). Bekapi mogu da posluže u ovu svrhu … AKO ih imate! Ali čak i tada, gubljenje onoga što je urađeno u toku nekoliko dana između dva bekapa, može biti veoma demotivišuće.

Modularnost

Onim ljudima koji su pisali programe u tradicionalnijim “programskim jezicima”, biće blizak koncept modula, include fajlova itd.

Moduli koriste ideju funkcija, ali idu korak dalje. Umesto da prosto grupišu i drže zajedno skup komandi, moduli grupišu i drže zajedno skupove funkcija (i pridruženih vrednosti). Na ovoj strani, predstaviću koncept odvojenih fajlova, kao “modula”.

ksh, i ostali sh-jezici, imaju komandu tačka "." , kao način da “sorsuju”, tj. uključe (sorce/include)druge fajlove. Ovo je bukvalno isto što i “#include" direktiva u mnogim drugim jezicima. Najčešće se koristi samo kao pogodnost da se “usisa” neki konfiguracioni fajl, koji jednostavno ima odgovarajuća podešenja promenljivih. U suštini, nema razloga da se ovo ne koristi i za uključivanje celih funkcija.

Ali zašto to raditi?
Jer je to razumno, i u svrhu otklanjanja grešaka.

Razumnost

Budimo iskreni: teško je sa pažnjom i u celosti pregledati neku shell skriptu od 1000 i više linija koda. Ipak, kako skripta postaje sve veća, na neki način je još i VIŠE važno da se ovo uradi! Ključno je obezbediti da se promena na jednom mestu ne odrazi negativno na drugim mestima u kodu.

Nasuprot tome, ako ste dovoljno disciplinovani da dodatno izdelite svoj kod tako da se, na primer, sve komande za manipulaciju fajlovima nalaze u jednom jedinom fajlu, vi imate daleko manju “metu” koju treba proveriti, onda kada pravite izmene koje utiču na “manipulaciju fajlovima” u vašem programu.

Otklanjanje grešaka u programu

U složenijim programima postaje veoma važno da se testiraju određene pod-funkcije vašeg programa. Protrčavanje kroz program, koji može imati 10 ili više grananja, nije praktično. Potrebno vam je “testiranje jedinice” (unit testing).

U manjim skriptama lako je samo napraviti brzu kopiju i onda “zloupotrebiti” kopiju za brzo-i-prljavo testiranje, odsecajući delove koda koji nisu neophodni za prinudni test. U većim, složenijim programima, postoji ozbiljnija opasnost da će jedan takav pristup završiti slučajnim odsecanjem dela koda koji je ključan za normalno funkcionisanje programa.

Ali šta ako je program već “isečen” u unapred isplanirane, samostalne sekcije?
U tom slučaju od ovih “modularnih sekcija” možete izabrati samo one koje su vam neophodne, a takođe i uskakati pravo u rutine koje vam trebaju, uz dobar stepen sigurnosti.

Još jedna prednost, kada imate module, je to što je onda lakše napisati test snopove (test harnesses), specifične za određene zadatke. Za veliki program, možete imati kolekciju skripti samo za testiranje, koje čuvate zajedno sa samim programom. Tada, kad napravite izmenu u određenoj sekciji, možete ponovo pokrenuti test skriptu da potvrdite da u tom modulu niste ništa pokvarili.

Važna ograničenja

NB: budite sigurni da vaši “moduli” sadrže samo funkcije, i možda poneko dodeljivanje vrednosti promenljivim. U modulima ne treba da bude koda koji radi na najvišem nivou programske logike. Izvršavanje komande

. prog_somemodule

ustvari ne bi trebalo da RADI ništa, osim definisanja funkcija i promenljivih.

Banalizovani primeri

Evo nečega da pogledate, što demonstrira gore navedene principe. Ovo je krajnje beskorisno, osim što je, nadamo se, prosvetljujuće :-)

Top level 'prog'

#!/bin/ksh -p

CODEDIR="."
. $CODEDIR/prog_status
. $CODEDIR/prog_mungedata

get_status
if [[ $? -eq 0 ]] ; then
rotate_data
fi

'prog_status'

# početak prog_status
get_status() {
    ps -ef|grep apache
    if [[ $? -eq 0 ]] ; then
        return 0
    else
        return 1
    fi
}

'prog_mungedata'

# početak prog_mungedata

# rotate_data: imajte u vidu da će pre ovoga verovatno trebati da pozovete funkciju
# get_status, da budete sigurni da program nije aktivan pre rotacije log-a
rotate_data() {
mv -f /var/log/apache.1 /var/log/apache.2
    mv -f /var/log/apache /var/log/apache.1
}

'tester'

#!/bin/ksh -p

# Testirajte snop za 'prog' rutine.
# sada samo testiramo da potvrdimo da get_status radi pravilno

get_status
if [[ $? -eq 0 ]] ; then
    print According to get_status, program radi sada
else
    print According to get_status, program NE radi sada
fi

Završne napomene: include-ovi i Makefile-ovi

Važno je napomenuti da postoji puno načina da se odradi konačna “isporuka”, tj. instalacija koda. U gornjim banalnim primerima, kod je “sorsovan” iz trenutnog direktorijuma. Međutim, u stvarnom svetu, to nije dobra praksa. Bolje bi bilo sorsovati kod iz CODEDIR=/opt/prog/libexec, ili nekog sličnog direktorijuma.

Postoji i još jedna mogućnost: različite module možete čuvati razdvojeno za potrebe pisanja koda, a za instaliranje programa možete jednostavno sami uraditi "include"-ovanje, povezujući fajlove u jedinstvenu shell skriptu pre instalacije.
U neku ruku, ovo se može posmatrati slično kao “povezivanje” objektnih fajlova, da se instalira jedan izvršni objekat.

Pošto "cpp" ne volikomentare u '#' stilu, (a vi ćete želeti da koristite komentare u '#' stilu u svojim shell programima!!) evo brzog Makefile primera kako da se lako uradi ovakva vrsta stvari:

yourprog:    main.ksh incfile1 incfile1
    awk '$$1 == "AWKinclude" {system ("cat "$$2);next;} \
             {print}' main.ksh > $@

Zatim u vašem programu main.ksh, upotrebite komandu "

AWKinclude incfile1
" umesto one u cpp stilu "#include "

Za elegantan, koristan primer u ovom stilu, možete pogledati u moj zrep "source code" direktorijum


POČETAK tutorijala
Prethodno poglavlje: Poređenja dobrog naspram lošeg koda

Ovaj materijal je zaštićen autorskim pravima od strane Philip Brown-a





Published (Last edited): 24-08-2012 , source: http://www.bolthole.com/solaris/ksh.html