A mottók:
"Mindenhez több mint egy út vezet."
A programozó három fő erénye a Lustaság, a Türelmetlenség és az Önhittség.
Perl-ben csak a számítógép hardware korlátai érvényesülnek: egy teljes file-t képes beolvasni egy string változóba (ha van elég memória), tetszőleges mélységű rekurzió futtatható benne (ha van türelmünk és memóriánk). Asszociatív tömbök elérését hash táblákkal gyorsítja (ami meglepően hatékony programok írását teszi lehetővé). Nagyon gyors és rugalmas mintaillesztő algoritmusa van szövegek keresésére és cseréjére (eredetileg szövegfile-ok feldolgozására találták ki, mint azt a neve is mutatja: Practical Extraction and Report Language). Képes bináris adatokkal is dolgozni, és ezekből bonyolult adatstruktúrákat felépíteni. Az adminisztrációs feladatok megkönnyítésére az asszociatív tömbökhöz adatbázis file-okat rendelhetünk, melyek szerkezetét egy gyakorlott programozó maga is megadhatja.
Az 5-ös verziótól kezdve már használhatjuk a moduláris programozást támogató nyelvi konstrukciókat, sőt már Objektum Orientált eszközöket is.
A Perl-ben setuid programok sokkal biztonságosabban írhatók, mint C nyelvben az adatfolyam követését biztosító funkciók miatt (ld.: -T kapcsoló). Elkerülhetünk egy csomó egyszerű hibát, amit a C programban csak debuggolással fedeznénk fel. Egyszerűen sokkal jobb a fejlesztési idő/futtatási idő arány ha egy ritkán használt, vagy futási időben nem kritikus (pl. CGI program) program írásánál. Szerintem akkor is érdemes ehhez a nyelvhez fordulni, ha egy shell script-ekből és C programokból álló keveréket szeretnénk létrehozni, vagy csak tesztelni szeretnénk egy ötletünket, amit - ha beválik - persze később megírhatunk C-ben.
Ez a leírás UNIX rendszert használó gépeken használható fel igazán. A konkrét nyelvi részek a DOS, OS/2 és Windows alatt futó Perl interpreterekre is igaz, de a környezetfüggő részek és a példák csak UNIX alapú rendszereken mennek.
ennyit a "rövid" összefoglalásról...
Indulás
Kezdetnek mindjárt megnézhetjük a minimális Perl programot, ami a "Hello World!!!"
szöveg kiírásához kell:
#!/usr/local/bin/perl print "Hello World!!!\n";Már ebből a picike programból egy csomó hasznos dolgot meg lehet tudni:
perl <programnév>
paranccsal lehetne lefuttatni.
print
utasítással
megadható, és az utasítást mindíg egy ";" zárja be.
Három alapvető adatstruktúra található a nyelvben: skalár, skalárok tömbje és az asszocitív tömb. Ezeket - mint azt későbbiekben látni fogjuk - mutatókkal is lehet kombinálni, így lényegében mindenféle adatstruktúrát megalkothatunk. A normál tömbök indexe - általában - 0-val kezdődik. Az asszociatív tömböket szövegekkel kell indexelni.
A változó nevének első karaktere határozza meg annak típusát:
$
skalárokat,
@
számmal indexelt és a
%
asszociatív tömböket jelöl.
Példák:
$days # egyszerű skalár $days[3] # days nevű tömb negyedik eleme @days # az egész tömb ($days[0], .. , $days[$#days]) $days{'Feb'} # days nevű asszociatív tömb egy eleme %days # az egész asszociatív tömb (kulcs, érték párok) $#days # days tömb utolsó indexe
Az alprogramokat még a &
jellel is megjelölhetjük. Erre akkor
lehet szükség, ha az alprogramot deklarációja előtt szeretnénk használni.
Függvényre a deklarációja után már a &
szimbólum nélkül is
hivatkozhatunk (ez - a nyelv előző verziójától eltérően - minden
függvényre alkalmazható).
A változók nevei egyébként a típusuknak megfelelő külön szimbólumtáblába
kerülnek, tehát használhatunk azonos nevű tömböt, asszociatív tömböt és
skalárt. (Ekkor $ize[0]
az @ize
tömb része, nem
pedig az $ize
változót helyettesíti.)
A változók nevei betüvel kell hogy kezdődjenek, és tetszőleges alfanumerikus karakterrel, illetve aláhúzásjellel folytatható. A változó neve nem kell, hogy megadott legyen, akár egy kifejezés is állhat helyette, melynek aktuális értéke lesz a valódi név!
Vannak speciális változónevek alapvető paraméterek jelölésére. Ezek az
Például az int(<STDIN>)
eredménye egy egész szám lesz, amit
a bemenet egy sorából állít elő az int
függvény, de a
sort(<STDIN>)
eredménye egy lista lesz, amit a bemenet
összes sorának beolvasása után a sort
függvény rendezéssel állít
elő!
Az aritmetikai műveleteknél a számok bináris formára konvertálódnak, így ezek pontosságát a processzor korlátozza. Vannak persze kiegészítő modulok tetszőleges pontosságú számok kezelésére is.
Feltételek vizsgálatánál csak az üres szöveg, illetve a 0 érték jelent hamisat.
A skalár változóknak alapvetően két állapota lehet: definiált, vagy definiálatlan.
Ezeket a defined
, illetve undefined
függvényekkel
kérdezhetjük le. Egy változó addig definiálatlan, amíg valaki nem ad neki értéket,
vagy nem definiálja explicit módon. Definiálatlan változónak - a környezetétől
függően - 0 vagy üres szöveg értéke van.
Példák:
$i = 2; # egész $f = 2.3; # racionális $szam = 1_000_000_000; # ez egy nagy egész $hexa = 0xffeedd; # hexadecimális szám $szoveg = "Ez egy szoveg"; # egy szöveg print "Valami\n"; # egy szöveg megjelenítése print <<VEGE; # hosszabb szöveg megjelenítése Valami # "Itt a dokumentum" stílusu VEGE # adatbevitellel (VEGE a zárószimbólum) $szoveg = <<VEGE; # $szoveg = "ez is szoveg\n" ez is szovega # ez is megy VEGE fv(<<EGY, <<KETTO); # sőt ez is! elso parameter EGY masodik parameter KETTO
@tomb = ('elso', 2, $harom); # háromelemű tömb %szinek = ( # asszociatív tömb 'piros' => 0x00f, 'kék' => 0x0f0, 'zöld' => 0xf00, );
És az utóbbival ekvivalens alak:
%szinek = ( 'piros' , 0x00f, 'kék' , 0x0f0, 'zöld' , 0xf00, ); #egyszerű felsorolás, párosával
Értékadásokban (rész)tömböket is értékül adhatunk. Ezekben az esetekben a balérték listája az első elemtől kezdve addig töltődik fel, amíg van új elem a jobb oldalon. Az értékadás akkor és csak akkor érvényes, ha a baloldalon legális balértékek szerepelnek.
($a,$b,$c)=(1,2,3) #a változók sorban értéket kapnak ($a,$b,@maradek)=@valami #ez is helyesTömb balértékként használata csak utolsó elemnek érdemes, mert egy korábbi tömb az összes jobboldalt magába olvassa. Ez jó a lokális paraméterek átvételénél.
@tomb=() #üressé teszi a tömböt $#tomb=$[-1; #a tömb hosszát -1-re állítja
Skalár környezetben a tömb felhasználása a tömb aktuális hosszát adja vissza.
Értékadásnál a résztömbök automatikusan elemenként bemásolódnak, így a keletkező tömb homogén lesz.
@tomb=(@lista1,@lista2,&alprg)Egy asszociatív tömb skalár környezetben visszaadja, hogy van-e benne kulcs-érték pár. Ez csupán arra jó, hogy a hash-elő algoritmus hatékonyságát vizsgáljuk.
A Perl program utasítások és dekralációk egymásutánja, amelybe megjegyzéseket
a #
jel használatával tehetünk. Ennek hatására a Perl interpreter
a sor végéig lévő szövegrészt megjegyzésnek tekinti.
Annak ellenére, hogy a nyelv UNIX-szűrő jellegű nyelvi elemeket is tartalmaz, minden utasítás csak egyszer kerül végrehajtásra, kivéve, ha ciklusban szerepel.
A nyelvben az utasítások és dekralációk szabadon - akár keverve is, mint
egy C++ programban - követhetik egymást. Megkötés
csak az alprogramok hívására van: a még nem deklarált alprogramot csak a
&
szimbólum használatával lehet meghívni.
utasítás if EXPR utasítás unless EXPR utasítás while EXPR utasítás until EXPREgy üzenet kiírása feltételtől függően:
print "Hello kedves olvasó!\n" if $bobeszedu_program;
{
és }
jelekkel közbezárt
utasítássorozat. (Itt fontosak a {
és }
jelek,
még egyetlen utasításnál is!)
Ez alapján a lehetséges formák:
if (EXPR) BLOKK # BLOKK végrehajtódik ha az EXPR igaz if (EXPR) BLOKK1 else BLOKK2 # ha EXPR igaz akkor BLOKK1, egyébként BLOKK2 # lesz végrehajtva if (EXPR) BLOKK elsif (EXPR) BLOKK ... else BLOKKAz if utasítás szintaxisa itt egyértelmű lesz, mivel a BLOKK nem állhat egyetlen utasításból.
CIMKE while (EXPR) BLOKK CIMKE while (EXPR) BLOKK continue BLOKKA while ciklus törzsében végrehajtott
next
utasítás
hatására a vezérlés a continue BLOKK-ra kerül, majd újra elindul
a ciklusmag.
CIMKE for (EXPR1; EXPR2; EXPR3) BLOKKEz a szokásos C-beli ciklus formája.
for($i = 1; $i < 10; $i++) { $i = 1; ... while($i < 10) { } ... } continue { $i++; }
CIMKE foreach változó (TOMB) BLOKKEz a shell-ekben meglévő ciklus egy változata. Itt a változó sorban felveszi a TOMB elemeit értékül, és így indul el a ciklusmag.
CIMKE BLOKK continue BLOKKEz a végtelen ciklus volt...
A ciklusokban használható a next
, a last
és a redo
utasítás, melyek a ciklusbeli utasítások végrehajtását vezérlik. A fent említett next
hatására a futás a ciklus elejére kerül, és a feltétel újratesztelésével folytatódik a működés. A redo
ehhez hasonló, csak itt a feltétel tesztelése nélkül kerül a végrehajtás a ciklus első utasítására. A last
pedig a ciklusból kiugrik, és az utána következő első utasításon folyik tovább a program végrehajtása.
A három utasítás használatában érdekesség, hogy mindegyiket címkézni is lehet és ekkor az ugrások az adott címkével ellátott ciklusra vonatkoznak.
Mivel a blokk egy egyszer lefutó ciklusnak tekinthető, ezért ezek az utasítások blokkban is használhatóak.
A switch utasításra nincs külön forma, de van rá egypár lehetséges megoldás, például:
SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1; }A
/^abc/
alakú feltételek mintaillesztésre
szolgálnak. Ha egy minta illeszkedik a $_
változó tartalmához,
akkor a hozzá tartozó feltétel második tagja is kiértékelésre kerül, azaz
a do blokk is végrehajtódik.
A C nyelvben érvényes szabályok érvényesek, és még van egypár - shell script-ekből ismerős - új operátor.
operátor | kiértékelés iránya | leírás |
---|---|---|
lista (,) | balról jobbra | kifejezések listája |
-> | balról jobbra | hivatkozás |
++,-- | nem asszociatív | növelés, csökkentés |
** | jobbról balra | hatványozás |
!,~,\ és unáris +,- | jobbról balra | nem, bináris nem, címoperátor, +, - |
=~,!~ | balról jobbra | szöveg illeszkedés, nem illeszkedés |
*,/,%,x | balról jobbra | szorzás, osztás, modulus, ismétlés |
+, -, . | balról jobbra | összeadás, kivonás, konkatenáció |
<<,>> | balról jobbra | balra, illetve jobbra shift |
unáris operátorok | nem asszociativ | pl. file tesztelés -f |
<,>,<=,>=,lt,gt,le,ge | nem asszociatív | szám illetve szöveg összehasonlítása |
==,!=,<=>,eq,ne,cmp | nem asszociatív | szám illetve szöveg összehasonlítása |
& | balról jobbra | bináris AND |
|,^ | balról jobbra | bináris OR és XOR |
&& | balról jobbra | logikai AND |
|| | balról jobbra | logikai OR |
.. | nem asszociatív | tartomány |
?: | jobbról balra | feltételes értékadás |
=, +=, -=, *= ... | jobbról balra | értékadás operátorai |
, => | balról jobbra | vessző és kulcs operátor |
lista operátorok | nem asszociatív | lista manipulációk |
not | balról jobbra | logikai NEM |
and | balról jobbra | logikai ÉS |
or, xor | balról jobbra | logikai VAGY-ok |
Itt csak az ismeretlennek tűnő operátorokat fogom kiemelni:
"ha"x3 == "hahaha"
"ha"."ha" == "haha"
-f "hello.c"
akkor igaz, ha a hello.c
file létezik
<=>
szerepel itt.
Ennek -1 az értéke, ha az első szám nagyobb, 1, ha a második, és 0, ha
egyenlő a két szám. Ez az operátor - az előbb említett cmp
operátorhoz hasonlóan - főleg rendezéseknél használható jól.
<
és a >
. Ha egy file
leíróját ilyen jelek közé rakjuk, akkor egy sort olvashatunk
belőle. A beolvasott sor automatikusan a $_
változóhoz rendelődik, ha nem adunk meg mást.
Egy egyszerű cat (UNIX cat parancs) így is leírható:
while(<STDIN>) { print $_; # print; is lehetne, hiszen az $_ az # alapertelemezett argumentum }
általában | hivatalos jelölés | értelme | megjegyzés |
---|---|---|---|
'' | q{} | szöveg literál | ez a "szó szerinti" szöveg literál |
"" | qq{} | szöveg literál | változókat helyettesíti a szövegben |
`` | qx{} | parancs | az adott szöveget, mint egy shell parancssort végrehajtja |
qw{} | a szövegből egy szólistát csinál | pl.: paraméterátadás | |
// | m{} | mintaillesztés | változókat értékükkel helyettesíti |
s{}{} | csere | változókat értékükkel helyettesíti | |
tr{}{} | betücsere | az szövegeket mint cseretáblát használja |
Szövegkeresés netovábbja.
$sor =~ /keresettszo/;
$sor =~ s/eredeti/ujszo/;
($erdekes_szo) = /\s+(\w+)$/;
i | kis- és nagybetüket nem különbözteti meg |
m | többsoros szövegben keres |
s | a szöveget egyetlen sorként kezeli |
x | kibővített keresési mód |
Az i
módosító használatával így a /perl/i
kifejezés a PeRL
szövegre is illeszkedni fog.
Az x
módosító tulajdonképpen arra jó, hogy egy kicsit lazább
szintaxszissal írhassuk le a kereső kifejezéseket. Ezzel már lehetőség van
többsoros, sőt megjegyzésekkel tűzdelt kifejezés írására is!
()
csoportosító operátortól eltekintve.)
Az alapok
\ | a következő karakter speciális |
^ | a sor elejéhez illeszkedik |
. | egy tetszőleges karakterhez illeszkedik (kivéve az újsort) |
$ | sor végéhez illeszkedik |
| | alternatívák jelölése |
() | csoportosítás |
[] | karakter-osztály kijelölése |
A .
csak akkor fog az újsor karakterhez illeszkedni, ha erre
az s módosítóval külön megkérjük, pl.:
$szoveg = <<VEGE; Tobbsoros szoveg, amelyben a PERL perl szavakat kell majd megtalalni. VEGE print "illeszkedik/s\n" if $szoveg =~ /PERL.perl/s; # igaz print "illeszkedik/\n" if $szoveg =~ /PERL.perl/; # hamis
A sor eleje és vége inkább rekord elejét és végét jelenti, hiszen a nyelvben meg lehet határozni, hogy mi válassza el a sorokat ($*). Alapesetben ez persze az újsor karakter, de ezt meg lehet változtatni...
karaktersorozatok Egy egyszerű kifejezés ismétlődését a következőkkel lehet jelölni:
* | 0 vagy több |
+ | 1 vagy több |
? | 0 vagy 1 |
{n} | pontosan n-szer |
{n,} | n-szer vagy többször |
{n,m} | n <= ismétlődések száma <= m |
Alapértelmezés szerint ekkor a leghosszabb ismétlődés fog illeszkedni ezekhez a
részekhez. Ha minimális számu illeszkedést szeretnénk,
akkor mindegyik után odatehetjük a ?
jelet:
"hhhhhh" =~ /h{2,4}/; # itt "hhhh" fog illeszkedni "hhhhhh" =~ /h{2,4}?/; # itt csak "hh"
\t | tabulátorjel |
\n | újsor |
\r | return |
\f | form feed |
\v | vertical tab |
\a | csengő |
\e | escape |
\033 | oktális számrendszerben megadott karakter |
\x1b | karakter hexadecimálisan |
\c[ | kontrol karakter |
\l | kisbetü |
\u | nagybetü |
\L | kisbetü \E-ig |
\U | nagybetü \E-ig |
\E | ... |
\Q | metakarakterek normálisak \E-ig |
\w | "szó" karakter (alfanumerikus és _) |
\W | nem-szó karakter |
\s | whitespace |
\S | nem whitespace |
\d | számjegy |
\D | nem számjegy |
\b | szóhatárhoz illeszkedik |
\B | nem szóhatár |
\A | string elejéhez illeszkedik |
\Z | string vége |
\G | oda illeszkedik, ahol az elöző illesztés végetért |
Az x
módosító használatával még lehet használni más
dolgokat is, de ezek szerintem már csak igen-igen ritkán kerülnek
elő.
()
karaktereket kell használnunk. Ha ezekkel bezárunk egy karaktersorozatot
a reguláris kifejezésben, akkor az ahhoz illeszkedő karakterekre a
kiejezésen kívül is hivatkozhatunk.
Ha egy csere környezetben használjuk, akkor az így kapott karaktersorozatokra a $1, $2, $3 ... változókkal lehet hivatkozni:
s/^([^ ]*) *([^ ]*)/$2 $1/; # első két szó felcserélése if(`date` =~ /(..):(..):(..)/) { # idő kiírása print "ora: $1, perc: $2, masodperc: $3\n"; }
Ha lista környezetben használjuk az illesztést, akkor a kiválasztott értékeket közvetlenül is megkaphatjuk:
($ora, $perc, $masodperc) = (`date` =~ /(..):(..):(..)/);
Ez a rész iszonyú nagy, és csomó olyan információt tartalmaz, amit már
amúgy is ismer az ember (legalábbis a C programokban használta már őket).
Itt csak néhány speciális dolgot fogok ismertetni, ami Perl jellegzetesség.
Ha valaki ismeri a szokásos C függvényeket, akkor azokat bátran használhatja,
bizosan megvan. Ha nem úgy viselkedik, ahogy várta, akkor érdemes
igénybe venni a POSIX modult:
Ha valakinek még ez sem elég, akkor igénybeveheti a különböző modulokat.
Már a nyelvvel együtt lehet találni adatbáziskezelő kiterjesztésektől
kezdve a terminálkezelő függvényekig sok mindent. Ezeken kívül az
Internetben legalább száz új modul kínál kiterjesztéseket különféle
nyelvek és könyvtárak felé (pl.: SQL adatbázikezelés, X11 grafikus felület,
Prolog...).
Az így megnyitott file-okat a close-val lehet lezárni, és
I/O műveletekben lehet használni:
Ha az awk-os neveket szeretnénk használni, akkor a
A file-ok "objektum-szerű" használatához a
A változókból itt is csak a legfontosabbakat fogom megemlíteni:
Alprogram hívása akkor megy ilyen egyszerűen ha az az őt tartalmazó modulban
látható. Ha ettől eltérő modulban lett deklarálva, akkor modulhivatkozással,
vagy valamilyen objektum-orientált technikával kell meghívni a kívánt
eljárást (ld. később).
type glob
Alap esetben egy egyszerű programban minden a main modulba
kerül be. Ha leírjuk a package szót, akkor az ez után következő
deklarációk már az új modulba fognak tartozni. A modul neveihez a ::
hivatkozás operátorral férhetünk hozzá (ez régen egy ' jel volt, de
az egyszerűbb olvashatóság érdekében, meg a C++ programozók kedvéért
ez megváltozott).
A modulhoz a modul nevével megegyező szimbólumtábla tartozik, ami lényegében
egy asszociatív tömb:
Egy modulban lévő nevekhez a use kulcsszóval férhetünk
hozzá:
Perl 4-ben kicsit nehézkes volt a bonyolult adatstruktúrák kezelése, de
most már vannak referenciák, így már mindazt a borzalmat el lehet követni,
amit egy C programban csak el tudunk képzelni. Sőt még többet is, mert
egy C programban nem lehetett a változóneveket menet közben manipulálni.
No persze a blokk lehet bonyolultabb is:
Amit a Perl objektumokról tudni kell:
Egy osztályban csak a metódusok öröklésére van támogatás az @ISA
tömbbön keresztül. Ez egy modul neveket tartalmazó tömb. Ha egy metódust
nem található meg az aktuális package-ban, akkor az ebben a tömbben
felsorolt modulok lesznek bejárva a hiányzó alprogramért. Ez egy
mélységi keresés lesz. Ha itt sem talál semmit, és van egy AUTOLOAD nevű
függvény, akkor megpróbálja ezzel előszedetni a hiányzó eljárást.
Ha ez a lehetőség sem járt sikerrel, akkor egy UNIVERSAL-nak nevezett
modulban fog keresgélni a rendszer.
Az @ISA tömb szépsége az, hogy menet közben is lehet módosítani, azaz
menet közben megváltoztathatjuk egy osztály leszármazási fáját!
Nyilvánvalóan az adattagok öröklésére is szükség van egy objektum-orientált nyelvben, ez a Perlben az @ISA tömb segítségével megvalósítható.
Alapvetően kétfajta metódus van:
Operátorok átlapolása
A Perl operátorainak nagyrésze átlapolható. Ehhez a %OVERLOAD tömböt kell használni, mely az átlapolt operátorokhoz tartozó függvényeket tárolja.
package Valami;
%OVERLOAD = (
'+' => \&myadd,
'-' => \&mysub;
# stb.
);
...
package main;
$a = new Valami 57;
$b = $a + 5;
Elképzelhető az az eset is, hogy nincsen definiált operátor az adott típusó változóhoz. Ennek kezelésére szolgál az %OVERLOAD tömbnek "fallback" nevű eleme. A "fallback" értékétől függően három eset lehetséges:
use POSIX;
Ezek után már bitosan meglesz az összes POSIX függvény.
néhány függvény...
($package, $filename, $line) = caller;
while(<>) {
chop; # $_ végéről vág
...
}
chop($cwd = `pwd`); # aktuális könyvtár
delete $tomb{"eleme"};
Ez a módja egy Perl prgram "fordításának".
while(($key,$value) = each %ENV)
{
print "$key=$value\n";
}
környezeti változók kiírása
(ld. még a változókat)
if exists $tomb{"eleme"} ...
sub kiir
{
my ($szoveg1, $szoveg2) = @_;
chop $szoveg1;
chop $szoveg2;
print $szoveg1, ':', $szoveg2, '\n\n';
}
open(FILE,"valami.txt"); # írás-olvasás
open(BE,"</etc/passwd"); # olvasás
open(KI,">/tmp/output"); # írás
open(FINGER,"finger @augusta |"); # olvasás pipe-ból
open(RENDEZ,"| sort >/tmp/ki");# írás pipe-ba
print FILE "Egy szor\n"; # "Egy sor" kiírása a FILE-ba
$sor = <BE> # sor olvasása
A PACKAGENAME modulban a változó típusától függően különböző
függvényeket kell megírni:
A no kulcsszó a use ellentettje, azaz
a láthatóságot megszünteti.
awk-on nevelkedett emberek itt otthon érezhetik magukat.
use English;
sort kell még beírni a programba.
use FileHandle;
sort kell beírni. Ezek után a következők ekvivalensek:
print KIMENET "Hello World!!!\n";
KIMENET->print("Hello World!!!\n");
$/ = "\n\n";
, mert a $/ = "\n\n";
több
üres sort is egyetlen határnak tekint.
($? >> 8)
-ként kaphatjuk meg.
Ez persze írható változó, tehát a $> = 0;
a root-tá válás egy módja, csak ez nem mindg fog bejönni :-).
print "Otthonom: ", $ENV{"HOME"}, "\n";
sub handler { # az első paraméter a signal neve
local($sig) = @_;
print "Elkaptam $sig-t!\n";
exit(0);
}
$SIG{'INT'} = 'handler';
$SIG{'QUIT'} = 'handler';
...
$SIG{'INT'} = 'DEFAULT'; # alapértelmezett
$SIG{'QUIT'} = 'IGNORE'; # figyelmen kívül hagy
Néhány Perl-beli esemény is kezelhető így. A
$SIG{__WARN__}
a warn által kiváltott, a
$SIG{__DIE__}
pedig a die által kiváltott
esemény lekezelésére szolgál. Mindkét esetben átadásra kerülnek
a warn, illetve a die paraméterei.
Alprogramok deklarálása:
sub NEV; # a NEV ismertté tétele
sub NEV BLOCK # deklarálás és definíció
Egy alprogramot nem kell előre deklarálni ahhoz, hogy használhassuk.
Az alprogramoknál a paraméterlistát sem kell deklarálni, mert ez
változhat. A hívott alprogram a paramétereket a @_ listán keresztül
kapja meg. Az alprogram utolsó utasításának az értéke lesz a visszatérési
érték, hacsak nincs egy return utasításban más megadva.
sub max {
my $max = pop(@_);
foreach $elem (@_) {
$max = $elem if $max < $elem;
}
$max;
}
Alprogram hívása:
&NEV; # az aktuális @_-t adja tovább
&NEV(LISTA); # Ha &-t írunk, akkor () kötelező
NEV(LISTA); # & elhagyható ha van () vagy már deklarált
NEV LISTA; # () elhagyható, ha a NEV már deklarált
$m = &max(1,2,3); # a hatás ugyan az
$m = max 1 2 3;
Névtelen alprogram létrehozása:
$alpref = sub BLOCK; # deklarálás
&$alpref(1,2,3); # hívás
Ez a technika főleg egyszer használatos alprogramoknál lehet hasznos,
például egy signal kezelő átdefiniálásakor.
Névtelen alprogramok definiált környezete
A névtelen alprogramokra jellemző, hogy mindig abban a környezetben futnak, amelyben definiálták őket, még akkor is, amikor az adott környezeten kívülről kerülnek meghívásra. Ez egy érdekes módja lehet a paraméterátadásnak, és callback jellegű kódrészeket lehet vele írni.
sub newprint {
my $x = shift;
return sub { my $y = shift; print "$x, $y!\n"; };
}
$h = newprint("Hello");
$g = newprint("Üdvözlet");
# Valamivel később...
&$h("világ!");
&$g("mindenkinek");
És az eredmény:
Hello, világ!
Üdvözlet, mindenkinek!
Beépített függvények átlapolása
Sok beépített függvény átlapolható, de ezt csak akkor érdemes kipróbálni, ha jó okunk van rá. Ilyen eset lehet a nem Unix-rendszereken a környezet emulálása.
Az átlapolás a subs
pragma segítségével történhet, például így:
use subs 'chdir'; #az átlapolandó beépített függvények
chdir $valahova; #az új chdir használata
sub chdir { ... } #a chdir megvalósítása
Ja kérem, ez egy "komoly" nyelv!
package
A Perl nyelv lehetőséget ad különböző láthatósági körök használatára.
Ezeket a láthatósági köröket moduloknak nevezhetjük, amelyet a
package kulcsszó vezet be. A package hatása
az adott blokk végéig, vagy a következő package-ig tart.
$elso = 1; # ez a $main::elso
package MODUL; # uj modul kezdete
$masodik = 1; # $MODUL::masodik
$elso = 1; # $MODUL::elso
$main::elso = 2;# $main::elso
A főmodul neveihez még a $::elso
hivatkozással is
hozzáférhetünk.
Szimbólumtábla
A modulok szimbólumtáblái futás közben elérhetőek, sőt módosíthatóak!!!
%main::
, avagy %MODULE::
.
Az itt lévő bejegyzésekhez a *nev
alakban is hozzáférhetünk.
local(*main::alma) = *main::korte;
local($main::{'alma'}) = $main::{'korte'};
Ez a példa egy új álnév létrehozását mutatja. Ezek után minden
korte
-re alma
-ként is hivatkozhatunk.
Az egyetlen különbség az, hogy az első fordítási időben értékelődik ki.
Konstruktor, destruktor
Itt az awk programozók megint otthon érezhetik magukat.
Ha a modulban BEGIN, illetve END
kulcsszóval jelzett blokkot definiálunk, akkor azok a package
használata előtt, illetve után lefutnak.
package hibakezeles;
BEGIN {
open(HIBAK,">./hibak");
}
END {
close(HIBAK);
}
sub kezeles {
local ($szoveg) = @_;
print HIBAK $szoveg, "\n";
}
A programban elindított BEGIN blokkokhoz képest fordított
sorrendben fognak lefutni az END blokkok.
use MODUL;
use hibakezeles kezeles;
A use használata ekvivalens a következővel:
BEGIN { require MODUL; import MODUL; }
Modulokat implementáló file-okat az @INC által meghatározott
könyvtárakban keresi a rendszer. A .pm, .pl
és
.ph
kiterjesztéseket nem kell kiírni a filenevek után.
A gondok mindíg a mutatókkal kezdődnek, de ez itt még álnevekkel is kombinálódik...
Referencák létrehozása
$scalarref = \$scalar;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
$arrayref = [1, 2, ['a', 'b', 'c']];
$hashref = {
'Ádám' => 'Éva',
'Clyde' => 'Bonnie',
};
$coderef = sub { print "Nem nyert!\n"; };
Referenciák használata
Nagyon egyszerű egy referanciát használni: a programban egy változó
neve helyére bárhova beírhatunk egy megfelelő típusú referenciát
tartalmazó vátozót.
$ketto = $$scalarref;
print "A program neve:",$$arrayref[0],"\n";
print "HOME=",$$hashref{'HOME'};
&$coderef(1,2,3);
Persze lehet mutatni mutatóra is:
$refrefref = \\\"valami";
print $$$$refrefref;
$ketto = ${$scalarref};
print "A program neve:",${$arrayref}[0],"\n";
print "HOME=",${$hashref}{'HOME'};
&{$coderef}(1,2,3);
&{ $inditas{$index} }(1,2,3); # megfelelő eljárás indul
$$hashref{"KEY"} = "VALUE"; # 1. eset
${$hashref}{"KEY"} = "VALUE"; # 2. eset
${$hashref{"KEY"}} = "VALUE"; # 3. eset
${$hashref->{"KEY"}} = "VALUE"; # 4. eset
Itt az 1. és 2., illetve a 3. és 4. eset egyenértékű.
print "A program neve:",$arrayref->[0],"\n";
print "HOME=",$hashref->{'HOME'};
Ennek balértéke bármilyen kifejezés lehet, amely egy referenciát
ad vissza. Ez az operátor el is hagyható {} vagy [] zárójelek
között (de tényleg csak közöttük!):
$array[$x]->{"valami"}->[0] = "január";
$array[$x]{"valami"}[0] = "január";
Ezzel el is jutottunk a többdimenziós C-beli tömbökhöz:
$tomb[42][4][2] += 42;
Szimbólikus hivatkozások
Ha a fent említett hivatkozásokban egy blokk nem egy változó
referenciájával, hanem egy string-gel tér vissza, a nyelv akkor
sem esik kétségbe. Szorgalmasan elkezdi böngészni a szimbólumtáblát,
hátha talál egy ilyen bejegyzést:
$nev = "ize";
$$nev = 1; # $ize
${$nev} = 2; # $ize
${$nev x 2} = 3;# $izeize
$nev->[0] = 4; # $ize[0]
&$nev(); # &ize()
$modulom = "MAS"
${"${modulom}::$nev"} = 5; # $MAS::ize
Ha ez a szabadság nem tetszik nekünk, akkor megköthetjük kezünket a
use strict;
használatával.
Lehet enélkül manapság nyelvet készíteni?
Objektum
Az objektum bármilyen referencia lehet, ami meg van áldva
azzal a tudással, hogy hol jött létre:
package ValamiUj;
sub new { bless {} } # 1. verzió
sub new { # kicsit bonyolultabban...
my $self = {};
bless $self;
$self->initialize();
return $self;
}
A referencia általában egy asszociatív tömb szokott lenni, amely
aztán az objektum saját kis szimbólum táblájaként szolgál...
Az objektumokat újra meg lehet áldani. Ekkor az objektum az új osztályba kerül, az eredeti osztályát "elfelejti", hisz egy objektum egyszerre csak egy osztályhoz tartozhat. Ezek után az új osztálynak kell gondoskodnia az eredeti adattagokkal kapcsolatos teendőkről. ld.Destruktorok
Osztály
Az osztály egy package. Nincs semmi különös jelölés arra, hogy ez egy
osztály, sőt még az inicializáló eljárást sem kell new-nak
hívni.
package A;
sub new {
my $type = shift;
my $self = {};
$self->{'a'} = 42;
bless $self, $type;
}
package B;
@ISA = qw( A ); # A a B ősosztálya
sub new {
my $type = shift;
my $self = A->new;
$self->{'b'} = 11;
bless $self, $type;
}
package main;
$c = B->new;
print "a = ", $c->{'a'}, "\n";
print "b = ", $c->{'b'}, "\n";
Metódus
Semmi különös jelölés nincsen rájuk, kivéve a destruktorokat.
package ValamiUj;
sub holvagyok {
my ($neve) = @_;
print "holvagyok: $neve\n";
}
Ez a következőképpen hívható:
ValamiUj->holvagyok();
package ValamiUj;
sub new {
my $self = {};
bless $self;
$self->{elso} = 1; # ez {"elso"}-vel egyenértékü
$self->{ize} = 42;
return $self;
}
sub kiir {
my $self = shift;
my @keys = @_ ? @_ : sort(keys(%$self));
foreach $key (@keys) {
print "\t$key => $self->{$key}\n";
}
}
És ennek hívása:
use ValamiUj;
$obj = ValamiUj::new();
$obj->kiir(); # C++ stílus
kiir obj "elso"; # "print" stílus
Destruktor
Destruktor is definiálható az osztályhoz, ha a modulban megadunk egy
DESTROY nevű eljárást. Ez akkor lesz meghívva, amikor az utolsó hivatkozás is megszűnik az adott objektumra, vagy a program futása befejeződik.
Nincs rekurzív destruktor-meghívás, vagyis az újraáldott objektum eredeti osztályára vonatkozó destruktort explicit meg kell hívni. Az objektumban tárolt adattagokra azonban a destruktor meghívása megtörténik.
Ötletek
Itt csak néhány ötletet mondok el, amik eddigi programjaimban jól jöttek:
perldoc perl # avagy
man perl # avagy
netscape http://augusta.inf.elte.hu/langs/perl/perl.html
__END__
sor is lezárhatja.
Ezek után beírhatjuk a program dokumentációját, így az nehezebben
vész el. Esetleg használhatjuk a perldoc formátumot,
amit a perldoc paranccsal nézhetünk meg, és
perlman, illetve perlhtml paranccsal
generálhatunk belőle más formátumokat.
Ezt a dokumentumot Frohner Ákos írta.
Néhány kiegészítéssel Szabó Richárd látta el.