teejuht
1. Sissejuhatus
2. Input/Output
3. Muutujad
4. Massiiv
5. Loogilised tingimused
6. if tingimus
7. for tsükkel
8. while konstruktsioon
9. Split ja Join ja spetsiaalne muutuja $"
10. Substitution ja Asendamine
11. Reverse ja Sort
12. Assotsiatiivne list
13. Käsurea argumendid
14. Erilised muutujad: $. ja $/
15. Programmi väljundi lugemine/programmi sisendi
andmine
16. Expansion
17. www.perl.org
18. ülesanded
19. Harjutusi ja näiteid
Perl on programmeerimisvahend mis on eelkõige mõeldud stringidega (ehk tekstiga) tegelemiseks. Ja perlis kirjutatud stringidega tegelevate programmide source'id on lühemad kui samasuguse funktsiooniga C source'id.
Olemas on ühelt poolt inerpretaatorid ja teiselt poolt kompilaatorid
ja linker'id.
|
|
lähteteksti ei pea kompilleerima, st uusi faile ei teki. | lähtetekst kompilleeritekse (tekivad objektifailid laiendiga .o) ja objektid tuleb linkida executable'teks (nt. laiendiga .b - binary). |
Nad täidavad programmi teksti rida realt ja võimalik, et nö. programm käib ja käib ja kui siis selgub, et prpgrammi tekstis on viga, siis täitmine katkestatakse. | Kompilleerimise ja linkimise ajal tavaliselt avastatakse vead ja nii peaks bianry ikka töötama. Mitte alati. |
Et täita interpretaatori jaoks mõeldud programmi teksti on vaja protsessorit ja interpretaatorit. | Et täita binary'it pole hiljem vaja kompilaatorit ega linkerit, ainult protsessorit. |
Perl'is pidavat olema nende mõlema ideoloogia head jooned:
- interpretaator selles mõttes, et ei pea kompilleerima (ei teki
uusi faile)
- kompillaator selles mõttes, et kogu programmi tekst kontrollitakse
vigade vastu enne täitmist üle.
Klassikalised perlis lahendatavad ülesanded on näiteks mitmetulbaliste nimekirjade sees toimuvad otsingud, asendamised, ümberjärjestamised ja muidugi CGI rakenduste programmeerimine. See materjal on esitatud sellises järjekorras, et lugedes järjekorras ei tohiks tekkida küsimusi a la "mis see on?" või "vt. tagantpoolt"; kuigi ma olen pannud mõnda kohta töötava näite, et teise ringi lugemise ajal oleks huvitavam :) Samuti on peale perl'iga tuvumist tark tegu hakata CGI-ga kätt harjutama.
Programm mis kirjutab midagi ekraanile:
1. #!/usr/bin/perl
2. print " tere inimesed\nminu nimi on Imre\n";
kirjutage need kaks rida faili nimega
avasona.pl
ja andke failile käivitamisõigus korraldusega
bash# chmod u+x avasona.pl või
bash# chmod 755 avasona.pl
ärge kirjutage rea numbreid!
Käivitamiseks andke korraldus
bash# avasona.pl
Selgitus:
1. sinna kirjutage tee, kus asub interpretaator,
asukohta on hea teha kindlaks nii: which
perl
2. ilmselt on see praktiliselt inglise keeles
NB! rida lõppeb semikooloniga; \n on reavahetus \t on tabulaator
Programm avab tekstifaili ja kirjutab sisu ekraanile:
tekstifail on selline:
imre on hea
lenin on halb
mihkel on kiuslik
rauno on osav
tanel on tark
perli script niisugune:
1. #!/usr/bin/perl
2. open (a, 'tekstifail');
3. @lausete_list=<a>;
4. print "Siis on kogu
tekst:\n @lausete_list\n";
5. close (a);
6. print "ja siin 0,
1, 2, 4, listi elemendid - antud juhul read\n";
7. print "0. $lausete_list[0]";
8. print "1. $lausete_list[1]";
9. print "2. $lausete_list[2]";
10. print "4. $lausete_list[4]\n";
Selgitus:
2. avatakse fail kusjuures temaga seostatakse
identifikaator 'a'
3. '@lausete_list' peab algama '@' märgiga
ja identifikaatoril peavad olema ümber märgid '< >'
4. kogu massiiv läheb listi @lausete_list
(elementide
vahelisteks piirideks saavad reavahetused)
5. suletakse fail aga muutujad (st. list) jääb
täidetuks!
6. @lausete_list'i elementide poole saab pöörduda
ka ükshaaval - $lausete_list[0]. $ on oluline.
Taga [ ] vahel olevat arvu nimeatakse listi elemendi indeksiks.
Programm saab klaviatuurilt muutujate väärtused:
1. #!/usr/bin/perl
2. print "See programm
on nõus ütlema kui vana te olete mingil aastal\n";
3. print "teie sünniaasta,
palun: ";
4. $synd = <STDIN>;
5. chop($synd);
6. print "Milline aasta
tulevikust teid huvitab, vabandage: ";
7. $aasta = <STDIN>;
8. chop($aasta);
9. $vanus = $aasta -
$synd;
10. print "Aastal $aasta te
olete $vanus aastat vana\n";
Selgitus:
4. muutuja $synd ootab väärtuse sisestamist klaviatuurilt
mis peab lõppema reavahetusega
7. käsk chop($synd) võtab muutuja väärtuselt
maha viimase sümboli - reavahetuse
Ülesanded!
1. Kirjutage neli programmi: korrutaja.pl, jagaja.pl, liitja.pl ja lahutaja.pl mis käituvad vastavalt oma nimetusele. Nad ootavad input'i klaviatuurilt ja annavad vastuse ekraanile.
Muuseas vastavad tehted on $i*$j, $i / $j, $i + $j ja $i -$j; kusjuures astendamine toimub selliselt:
#!/usr/bin/perl
$i=2;
$j=5;
$aste = $i**$j;
print "$i ^ $j = $aste\n";
tulemus: 2 ^ 5 = 32
ja võimalik on ka arvutada jääki:
#!/usr/bin/perl
$i=5;
$j=2;
$j66k = $i % $j;
print "$i % $j = $j66k\n";
tulemus: 1
Kuidas jääk leitakse? Jääki saab leida vaid täisaevust. Õeldakse, et leida viis jagada kahega jääk. Jäägiks saab antud juhul sellise tehte tulemus:
jääk = viis - kaks * (selline täisarv, et korrutis oleks viis või viiest väiksem)
antud juhul
jääk = 5 - 2 * (2) = 5 - 4 = 1
teine näide:
8 % 3 = 2, sest 8 - 3*2 = 8 -6 = 2
Tähelepanuväärne on see, et kõikide paarisarvude jäk kahega jagamisel on null!
Jääki on praktiliselt vaja siis, kui programm peab näiteks reageerima erinevalt paaris ja paaritutele arvudele. Näiteks, etteruttavalt :)
#!/usr/bin/perl
while (1)
{
print "Sisestage arv: ";
$arv=<STDIN>;
if (($arv % 2) == 0)
{
print "sisestati paarisarv\n";
}
else
{
print "sisestati paaritu arv\n";
}
}
No võib mõelda, et jama, milleks ikka neid paaris ja paarituid arve eristada, aga tihti on vaja mingeid asju teha vaheldumisi; või koguni üle kolme ... nii, et on abiks.
Ehk pole kohane seda märkida siin, aga siiski: kui arvutis on installeeritud csh (C - shell), siis tõlgendab < > märkide vahele jäävat perl kui expansionit vajavat avaldist. Seda vaid siis kui < > vahele jääv ei saa olla 'file handle'. See on ka põhjus miks on tavaliselt otstarbekas csh intalleerida: iial ei tea mis kaval script kastab perli seda omadust. (nt. INN, ma arvan)
Näiteks kirjutab järgmine programm välja kõik käesoleva kataloogi .pl laiendiga failid ning nummerdab read:
#!/usr/bin/perl
@pl=<*.pl>;
$i=1;
foreach $e(@pl)
{
print "$i. $e\n";
$i++;
}
Perlis ei tule muutujaid deklareerida nagu C-is.
Muutujaid on kolme sorti:
1. Täisarvulised, et nt. arvutada või indekseerida massiivielemente (massiivi nimetatakse perlis listiks)
$i = 5;
2. Stringid ehk mitmest tähemärgist koosnevad järgnevused. Neid tähistavad muutujad algavad samuti märgiga $ (nii arvude kui stringide jaoks). Muide, perlis sõltub muutuja tüüp kontekstist kus teda kasutatakse. See lause omandab tähenduse ilmselt alles hiljem :)
$j = "Lähme homme kinno";
3. Massiiv mida nimetatakse perlis listiks on mitmest elemendist koosnevaks konstruktsioon. Listi tähistav muutuja algab '@' märgiga. Hiljem näeme, et on käske mis oskavad pöörduda erinevate listi elementide poole. Käskude split ja join abil saab teha stringist listi ja vastupidi.
@list = ("mina", "sina", "tema");
#!/usr/bin/perl
$seisund="ma olen naljane";
$vanus=28;
print "Ma olen $vanus ja $seisund";
print 'Ma olen $vanus ja $seisund';
Siin tuleks tähele panna, et "" ja '' on muutujate suhtes erinev tähendus.
On olemas üks kasulik käsk mida stringidele rakendadakse: chop - see eemaldab stringist viimase sümboli; Kui teda rakendada list'ile, siis eemaldab ta iga listi elemendi lõpust viimase sümboli. See toimub seni kuni elemendist on alles vaid nö. tühi string "".
Näide:
#!/usr/bin/perl
@list=("yks", "kaks", "kolm",
"neli", "viis", "kuus", "seitse");
while ($list[1] ne "")
{
print "@list\n";
chop(@list);
}
$i=0;
foreach $e(@list)
{
print "$i. $e\n";
$i++
}
millele vastab selline 'output':
bash# ch.pl
yks kaks kolm neli viis kuus
seitse
yk kak kol nel vii kuu seits
y ka ko ne vi ku seit
k k n v k sei
0.
1.
2.
3.
4.
5.
6. se
bash#
lihtsalt stringi puhul:
#!/usr/bin/perl
$str="hommik";
while ($str)
{
print "$str\n";
chop($str);
}
ja vastav väljund on selline:
bash #
hommik
hommi
homm
hom
ho
h
bash #
Ehk on vahest vajalik mõõta ära stringi pikkus:
#!/usr/bin/perl
$a="tere kah!";
$l=length($a);
print "Stringi \$a=\"$a\" pikkus
on ";
print "$l\n";
Nagu öeldud, mida muidu st. C -s nimetatakse massiiviks, seda nimetatakse perlis millegipärast list'iks. Kui ma tarvitan neid sõnu mõetlen nende all siiski üht ja sama asja.
Kui stringi võiks visualiseerida nii:
$muutuja = "Imre Peeter Priit";
siis vastav list oleks selline (kui elemendid eraldada välja tühikute pealt):
@muutuja = ("Imre", "Peeter", "Raul");
kui elemendid eraldada välja aga 'P' pealt:
@muutuja = ("Imre ", "eeter ", "riit");
Tuleb tähelepanna, et on olemas käsud
mis oskavad tegeleda list' elementidega eraldi: nt. kustutada viimast,
keerata järjekord tagurpidi. Ja samas on käske mis oskavad
tegelda vaid stringidega.
Niisiis, listi tähistav muutuja algab @ märgiga:
#!/usr/bin/perl
@aedviljad=("redis", "kaalikas",
"porgand", "kapsas");
@puuviljad=("ploom", "kreek",
"oun", "sidrun");
print "$aedviljad[3]\n";
print "$aedviljad[0]\n";
print "@puuviljad\n";
$puuviljaelementidearv=@puuviljad;
print "massiivis puuviljad
on $puuviljaelementidearv elementi\n";
Pange tähele kuidas saab määrata listi elementide arvu
$puuviljaelementidearv=@puuviljad;
ja pöörduda üksikute elementide poole (esimene 0, , teine 1 jne.).
Listi puhul on veel olulised tehted push ja pop; need võimaldavad vastavalt olemasolevale või loodavale listile lisada elemente juurde või neid sealt eemaldada. Uued elemendid sattuvad lõppu või eemaldatakse sealt.
#!/usr/bin/perl
@list=("yks", "kaks");
while (1)
{
print "Listi seis:\n";
print "@list\n";
print "Sisestage uus element:
";
$uus=<STDIN>;
chop($uus);
push(@list, $uus);
}
ja teine näide:
#!/usr/bin/perl
@list=("yks", "kaks", "kolm",
"neli", "viis", "kuus", "seitse");
while (@list)
{
print "@list\n";
pop(@list);
}
pop ja chop'i puhul tuleks ära märkida, et on võimalik ka otseselt kätte saada eemaldatud objekt:
chopped.pl:
#!/usr/bin/perl
$a="abcdefgh";
while ($a)
{
$chopped=chop($a);
print "$chopped\n";
}
popped.pl
#!/usr/bin/perl
@a=("ma","olen", "suur", "perlimees",
",vot!");
while (@a)
{
$popped=pop(@a);
print "$popped\n";
}
Võiks ütelda ka loogilised tehted. Nende tehete tulemus on tavaliselt 0 või üks ning selle vastavalt saab suunata if, while, for jt. konstruktsioonide edasist käiku. Nii, et esialgu lihsalt tunneme tehted ära ja pärast kasutame neid.
#!/usr/bin/perl
print "5 > 4 = ";
print 5 > 4;
print"\n";
print "5 < 4 = ";
print 5 < 4;
print"\n";
print "5 == 5 = ";
print 5 == 5;
print"\n";
print "\"mina\" eq \"mina\"
= ";
print "mina" eq "mina";
print "\n";
print "\"sina\" gt \"mina\"
= ";
print "sina" gt "mina";
print "\n";
$c="aaaa " gt "aaa";
$d="z" gt "a";
$e="a" gt "z";
print "See peaks veenma, et
\$e kui arvu väärtus on 0:\n";
$kokku=$c + $d + $e;
print "\$c + \$d + \$e = $kokku\n";
print "See peaks veenma, et
\$e kui stringi väärtus on \"\":\n";
print "isa";
print "$e";
print "maa\n";
Siin peaks tähele panema järgmist:
- print käsu jaoks on " ja $ märk erilise
tähendusega, kui soovime neid aga siiski lihtsalt märkidena kasutada
tuleb kirjutada \" või \$
- = on omistamiseks ja == loogiline tehe.
Näeme, et tõeväärtustehe
- omab väärtust 1 kui on tõene
tulemus
- omab väärtust 0 või
"" (st. tühi string) kui mittetõene tulemus
Tunnistagem kohe, et print käsu asemel oleks praegu olnud õigem kasutada C stiilis printf käsku: oleks saanud palju lühemalt:
#!/usr/bin/perl
printf ("5 > 4 = %d\n", 5 >
4);
printf ("5 < 4 = %d\n",5 < 4);
printf ("5 == 5 = %d\n", 5 == 5);
printf ("\"mina\" eq \"mina\"
= %d\n", "mina" eq "mina");
printf ("\"sina\" gt \"mina\"
= %d\n", "sina" gt "mina");
$c="aaaa " gt "aaa";
$d="z" gt "a";
$e="a" gt "z";
print "See peaks veenma, et
\$e kui arvu väärtus on 0:\n";
printf ("\$c + \$d + \$e =
%d\n\n",$c + $d +$e);
print "See peaks veenma, et
\$e kui stringi väärtus on \"\":\n";
print "isa";
print "$e";
print "maa\n";
Selgitus:
printf ("5 > 4 = %d\n", 5 > 4);
jutumärkide vaheline läheb trükkimisele kusjuures %d
asendatakse peale jutumarke oleva koma taguse tehte tulemusega. %d ootab,
et tehte tulemus on decimal ehk täisarv kümnendsüsteemis.
Konstruktsioon võimaldab vastavalt loogilise tehte tulemusele (kas 1 või 0) valida kahe võimaliku programmi täitmise tee vahel. Kasutatakse ka koos else ja elsif-iga (NB! "elsif", ei ole kirjaviga).
Stringide võrdlus:
#!/usr/bin/perl
$a="mees";
$b="naine";
if ($a eq $b)
{
print "muutujad \$a ja \$b on yhesuguse vaartusega\n";
}
print "Programmi lopp\n";
Arvude võrdlus:
#!/usr/bin/perl
$a=5;
$b=6;
if ($a == $b)
{
print "muutujad \$a ja \$b on yhesuguse vaartusega\n";
}
else
{
print "muutujad \$a ja \$b on erineva vaartusega\n";
}
print "Programmi lopp\n";
Selgitus:
- NB! \ märki kasutatakse erilise tähendusega sümbolite
trükkimiseks!
- Loogeliste sulgude vahele jäävad käsud moodustavad
terviku mida nimetatakse programmeerimises lauseks. Niisiis, if tingimus
kontrollib milline lause täidetakse ja peale seada jätkub programmi
täitmine if tingimuse järelt.
On olemas ka selline võrdlus:
#!/usr/bin/perl
$a=<STDIN>;
chop($a);
if (!$a)
{
print "\$a on tühi string ja pole mõtet edasi tegelda\n";
}
elsif (length($a) == 1)
{
print "String sisaldab vaid ühte tähte\n";
}
elsif (length($a) == 2)
{
print "Stringis on kaks tähte\n";
}
else
{
print "Tähti on palju .. \n";
}
Seda konstruktsiooni kasutatakse kui on tarvis migit tegevust (programmilõiku)
teatud arv korda korrata.
Näiteks on neli massiivielementi ja tahame
nad kõik välja trükkida.
#!/usr/bin/perl
@linnad=("tartu", "tallinn",
"voru", "elva");
for ($i=0; $i < 4; $i=$i+1)
{
print "$linnad[$i]\n";
}
print "\nProgrammi lopp\n";
See on tehtud natuke liiga C - vaimus. Aga siiski selgitus:
for ($i=0; $i < 4; $i=$i+1)
{
print "$linnad[$i]\n";
}
- kolm alumist rida moodustavad lause mida täidetakse seni kuni
seda arvab heaks for tsükkel
- esimese täitmise ajal on tingimuses sisalduva muutuja $i väärtus
0 ja tingimus (0 < 4) tõene miska lause täidetakse
- peale lause täitmist suurendatakse $i -d ühe võrra:
$i = $i + 1
- taas kontrollitakse tingimust ja see on tõene (2 < 4) ning
lause täidetakse teiset korda
- nii tehakse mitmeid ringe kuni tingimus enam pole tõene ja
sestap lauset enam ei täideta.
- minnakse for tsükli järel olevate käskude juurde
- pange tähele, et $linnad[$i] massiivi indeks on muutuja
see on kõige pikem ja tihti kasutatakse teda hoopis selliselt:
#!/usr/bin/perl
@linnad=("tartu", "tallinn",
"voru", "elva");
for ($i=0; $i < @linnad
; $i++)
{
print "$linnad[$i]\n";
}
siin juba natuke perlilikumalt - konstruktsiooni foreach abil:
#!/usr/bin/perl
@linnad=("tartu", "tallinn",
"voru", "elva");
foreach $linn(@linnad)
{
print "$linn\n";
}
Kaks viimast on veel selle poolest head, et for või foreach kohti pole vaja muuta isegi kui massiivi elemente juurde lisada või ära võtta.
for -i puhul on veel ehk see tähelepanuväärne, et või kasutada ka mitut muutujat:
#!/usr/bin/perl
for ($i=1, $j=-1; $i <=
5; $i++, $j--)
{
print "\$i=$i ja \$j=$j\n";
}
Ning veel selline viis teha tsüklit:
#!/usr/bin/perl
for (1..10)
{
print "tere\n";
}
Konstruktsioon on mõeldud nagu for -gi lause kordamiseks. Tingimust kontrollitakse alguses ja kui see on tõene siis lause täidetakse. Imselt peab see tingimus mingil ajal muutuma mittetõeseks muidu programm ei lõpekski. Aga see võib olla ka taotlus.
#!/usr/bin/perl
$i=2;
while ($i < 10)
{
print "nii
ta on \$i= $i\n";
$i=$i+1;
}
märkus:
$i -e ei ruugi järjekindlalt ühte juurde liitma. võib ka:
$i = $i + 2:
$i = $i -5;
$i = $i * 2:
Näiteks trükime kahe astmed kuni 256 -ni:
#!/usr/bin/perl
$i=2;
$j=1;
while ($j < 8)
{
$j=$j+1;
$i=$i*2;
print "2^$j
= $i\n";
}
Tõe huvides olgu siskohal meenutatud, et astendamist saab teostada ka nii: i^j = $i**$j :)
Vahest on oluline kasutada lõpmatuid tsükleid/korduvusi millest saab välja last'iga:
#!/usr/bin/perl
$i=0;
while(1)
{
$i++;
print $i;
if ($i > 6)
{
last;
}
};
Tihti on vaja üleminekut stringilt massiivile ja vastupidi; seda teostavad käsud split ja join. Vaatame nende kasutust.
Olgu meil string
"Imre,Mart,Kaur,Peeter,Raul"
milles on ilmselt viis liiget. Tahame teha sellest listi:
"Imre", "Mart", "Kaur", "Peeter", "Raul"
Seda teeb järgmine programm:
#!/usr/bin/perl
$i=0;
$tekst = "Imre,Mart,Kaur,Peeter,Raul"
;
@list=split(/,/,$tekst);
while ($i < 5)
{
print "$i. $list[$i]\n";
$i++;
}
ja kui tahame teha vastupidist, siis seda teeb selline programm:
#!/usr/bin/perl
$i=0;
@tekst = ("Imre", "Mart", "Kaur",
"Peeter", "Raul") ;
$list=join(",", @tekst);
print "$list\n";
Listi elementide join'imiseks sobib ka selline omistamine:
$string="@list";
kusjuures tekkivas stringis on endise listi elemendid tühikutega
eraldatud; See millega nad on eraldatud määratakse spetsiaalse
muutuja $" väärtusega. Nt. kui soovime, et listist ("neli",
"koera", "magavad", "aasal") saaks string "neli koera magavad aasal", siis
piisab ülaltoodud reast.
Kui aga soovime saada stingi "neliRkoeraRmagavadRaasal", siis on vaja
kahte rida:
$"="R";
$string="@list";
ja kõige olulisem on selline rakendus, mis on just abiks binary failide lugemisel:
$"="";
$string="@list";
meie näite kohaselt oleks tulemuseks:
"nelikoeramagavadaasal"
Tavaline on probleem kus perli program kirjutatakse eesmärgil viia automaatselt läbi mingid korrapärased asendamised. Midagi sellist võimaldab ka programm 'sed'. Olgu meil tekstifail ja me soovime seal sendada sõnad 'Mari' sõnadega 'Mart'.
Tere Mari,
kuidas Sul läheb? Olen
siin kaugel ja,
Mari, mõtlen ainult
Sinust. Teed on siin
ebaühtlased ja käänulised.
Mari, ma mäletan kuis
me need kunagi koos käisime.
Mari kallis, kirjuta mulle, kunagi!
Igavesti Sinu, Peeter
selline programm peaks tegema asja ära:
1. #!/usr/bin/perl
2. open (a, 'jutt');
3. @tekst = <a>;
4. $tekst_s=join ("",
@tekst);
5. print "originaal tekst on
siin:\n\n $tekst_s";
6. $tekst_s =~ s/Mari/Mart/g;
7. print "\n\nmuudetud tekst
on siin:\n\n $tekst_s\n";
Selgitus:
3. @tekst on massiiv mille elemendid on tekstifaili 'jutt' read; iga
elemendi lõpus on ka readvahetuse märk
4. join ühendablisti @tekst'i kokku stringiks ise midagi
juurde panemata ("")
6. g täht eelviimase rea lõpus tähendab global - kui
see ära jätta toimuks vaid üks asendus
11. Reverse ja Sort - Listi tagurpidi pööramine ja sorteerimine
Need on kaks nagu arvata võib praktilist võimalust: toome vaid kasutusnäiteid ja rakendust oskab igaüks ilmselt ise otsida :)
reverse.pl:
#!/usr/bin/perl
@list=("ma","sa","ta","me","te","nad");
foreach $e(@list)
{
print "$e\n";
}
@rev_list=reverse(@list);
print "\n\n";
foreach $e(@rev_list)
{
print "$e\n";
}
sort.pl:
#!/usr/bin/perl
@list=(7,8,9,2,5);
foreach $e(@list)
{
print "$e\n";
}
@sort_list=sort(@list);
print "\n\n";
foreach $e(@sort_list)
{
print "$e\n";
}
Non-ASCII match:
Selle kohta saab infi: man perlre (perl regular expressions)
nt. kui soovime trükkida välja tähti kasutades neile vastavaid ASCII koode kuuetesitkümnendsüsteemis, siis seda teeb programm:
#!/usr/bin/perl
print "Tere: \x52 \x53 \x54\n";
tulemus on:
R S T
Võib jääda mulje, et see on järjekordne muutuja struktuur ja vaid üks tarbetu vigurdamine, kuid selle rakendamine osutub erakordselt efektiivseks CGI programmides. Loomulikult saab kõik programmid ära programeerida assotsiatiivse list'i muutuja tüüpi ignoreerides, kui ehk pole sel mõtet :)
Niisiis, kui nö. tavalisele listile omistatakse väärtused nii:
@list=("a", "b", "c", "d", "e");
elementide poole pöördutakse nii:
$element=$a[1];
, siis
assptsiatiivse listi elementidele omistatakse väärtused nii (NB! %):
%ass_list=("Imre",28,"Jaan", 19, "Mari", 18, "Endel", 65);
ja elementide poole pördutakse nii:
$element={"Imre"};
kusjuures $elemendi väärtuseks saab 28.
Näide, mis ilmestab asja paremini; NB! key ja value on olulised võtmesõnad!
#!/usr/bin/perl
%person=("Imre",28,"Jaan",
19, "Mari", 18, "Endel", 65);
print $person{"Imre"};
print "\n";
print $person{"Endel"};
print "\n";
foreach $e (keys %person)
{
print "nimi: $e\n";
}
foreach $e (values %person)
{
print "vanus: $e\n";
}
Sisulisele küljele mõeldes on soovitav nii planeerida, et assotsiatiivse listi elemente on paarisarv. Ning oluline on teada, et nö. tavalist listi saab konverteerida assotsiatiivseks ja vastupidi. Nii:
%ass_list=@list;
@list=%ass_list;
See on vajalik kuivõrd assotsiatiivne list pakub spetsiifilisi võimalusi elementide poole pöördumiseks.
Ning veel üks konstruktioon pöörduda assotsiatiivse listi elementide poole:
#!/usr/bin/perl
%vanused=("Imre",28,"Jaan",
19, "Mari", 18, "Endel", 65);
while (($person, $vanus) =
each(%vanused))
{
print "$person on $vanus aastat vana\n";
}
CGI puhul on esialgu ehk hea käivitada Netscape'st selline perli script:
#!/usr/bin/perl
while (($muutuja_nimi, $vaartus)
= each(%ENV))
{
print "$muutuja_nimi = $vaartus\n";
}
See programm kirjutab välja user nobody keskkonna muutujate
väärused. Asi on nimelt selles, et kui keegi läheb Netscape'ga
mõnda serversse sisse, siis käsitleb server seda kui kasutajad
nobody mis kuulub gruppi nogroup. Ja neis õigustes käivitab
ta perli scripte ja võib isegi faile moodustada (uploadida samuti).
Niisiis, toodud progamm produtseerib ühe väjundi kasutaja õigustes
käsurealt käivitades ja teise Netscapes'st tööle tõmmates.
Ehk pole see CGI juures nii oluline aga hea on osata anda perli scriptile input'i käsurea argumentidena. Nt. nii, et
bash # korruta.pl 5 6
Korrutis: 5 x 6 = 30
bash #
Teeme selle ära. Esmalt käsurea argumendid lähevad spetsiaalsesse listi @ARGV kusjuures $ARGV[0] on esimene $ARGV[1] on teine jne. argument.
#!/usr/bin/perl
print "@ARGV\n";
ja nüüd korrutaja
#!/usr/bin/perl
$korrutis=$ARGV[0]*$ARGV[1];
print "Korrutis: $ARGV[0] x
$ARGV[1] = $korrutis\n";
Ja asjakohane on märkida, et programmi seest saab küsida ka programmi enda nime:
#!/usr/bin/perl
print "$0\n";
14. Erilised muutujad $. ja $/
Perliga on see asi, et pidevalt leiab vigureid ja nüansse. Üks on selline:
Muutuja $. mis on vaikimisi defineeritud peab arvet selle üle mitu nö. rida on sisendist loetud; kasutusnäide:
#!/usr/bin/perl
while (1)
{
$a=<STDIN>;
print "$. $a";
}
See on jälle lõpmatu tsükkel kust saab välja Ctl - C'ga.
Teine väike võte võimaldab määrata ära nö. reavahetuse märgi. Asi on selles, et
@a=<fh>;
täidab listi @a file handle'ga identifitseeritud faili sisuga kusjuures
elemendid saadakse tavalise reavahetuse (so. '\n') järgi. Kui enne
üledefineerida muutuja $/ väärtus, siis hakatakse elemente
vastvalt testiti eraldama.
Praktiline näide on selles kuidas saab pilti perli failiga Netscape'sse
lugeda:
pilt.pl:
#!/usr/bin/perl
print "Content-type: image/jpeg\n\n";
$/=EOF;
open (fh, "pilt.gif");
while ($l=<fh>)
{
print "$l";
}
close (fh);
Selgitus:
- tehke public_html'i toodud fail ja andke talle 755 õigused
- veenduge et samas kataloogis on pilt pilt.gif sobivate õigustega
(nt. 755)
- browseri Location reale kandes 'teie.serveri.nimi/~teie_nimi/pilt.pl'
peaks pildi ekraanile tooma :)
See ongi esialgu kõik; kirjutan juurdekui midagi uut avastan :)
15. Programmi väljundi lugemine/programmile sisendi andmine
Tihti on vaja perli scripte kasutada selleks, et mõne UNIX'i programmi väljundit töödelda. Nt. CGI'ga saata browerisse kui browser küsib. Ja see on täiesti võimalik ja isegi saavutatav väga loomulikul teel. Järgmised näited demonstreerivad mõnda võimalust.
#!/usr/bin/perl
open(fh, 'ls -l |');
@data1=<fh>;
chop (@data1);
foreach $e (@data1)
{
@data2=split(/ +/,$e);
if ($data2[4] > 100000) {
printf ("%5.2f MB %s\n", $data2[4]/(1024*1024),
$data2[8]);}
}
close (fh);
see programm loeb käesolevast kataloogist 'ls -l' i ja seejärel kirjutab välja vaid nende failide suuruse ja nime mis on suuremad 0,1 MB'st.
teine sarnane võimalus on seda teha nii:
#!/usr/bin/perl
@data1=`ls -l`;
chop (@data1);
foreach $e (@data1)
{
@data2=split(/ +/,$e);
if ($data2[4] > 1) {
printf ("%5.2f MB %s\n", $data2[4]/(1024*1024),
$data2[8]);}
}
NB! vaadekae need 'ülakomad' õiged saada!
ja järgnev on huvitav näide; tõsi praktiliselt mõttetu aga tehniliselt unix'ilik!
#!/usr/bin/perl
open (fh, '| gzip > xxx.gz');
$i=0;
while ($i < 1000)
{
print fh "$i nii on see siin ja nii on see
seal\n";
$i++;
}
close (fh);
toimub see, et print kirjutab väljundisse (fh'sse) ascii teksti mis aga enne faili saatmist käigult kokku pakitakse.
veenduge, et tekkiv fail on kasutatav:
bash# gunzip -c xxx.gz
(-c saadab gunzip'i väljundi konsoolile, sellega on vaja tavaliselt
ettevaatlik olla, aga kui on ascii pole hullu)
sellest ei tea ma palju aga vihjeks selline programmijupp:
#!/usr/bin/perl
while (<*>)
{
print "$_\n";
}
seletuseks ikkagi niipalju, et <*> expaneerub ehk laieneb käesoleva
kataloogi nimedeks, iga while'i ajal järgmine.
Ja $_ on selline ettedefineeritud muutuja mis oma väärtusi
saab just sellistes olukordades :)
Muide, et see expansion töötaks on vaja, et süsteemis
oleks olemas tchs või csh, ei mäleta kumb. Kasutaja shell võib
olla mis tahes.
Vot selline on perl!
1. Looge programm, mis küsib esmalt millise kujundiga soovite tegelda (ring, ristkülik, kolmnurk) ja siis vastavad andmed ning leiab valitud kujundi pindala. lahendus
#!/usr/bin/perl
print "kas soovite arvutada
ringi, kolmnurga voi ristkyliku pindala?: ";
$a=<STDIN>;
if ($a eq "ring\n")
{
print "sisestage raadius: ";
$r=<STDIN>;
$s=3.14*$r*$r;
print "Raadiusega $r cm'i ringi pindala on $s cm2\n";
}
if ($a eq "ristkylik\n")
{
print "sisestage yhe kylje pikkus: ";
$a=<STDIN>;
print "sisestage teise kylje pikkus: ";
$b=<STDIN>;
$s=$a*$b;
print "Ristkyliku pindala on: $s cm2\n";
}
if ($a eq "kolmnurk\n")
{
print "sisestage kolmnurga korgus: ";
$h=<STDIN>;
print "sisestage kolnurga alus: ";
$c=<STDIN>;
$s=$h*$c/2;
print "kolmnurga pindala on: $s cm2\n";
}