A Perl programozási nyelv – röviden
79/1
A Perl nyelvről általában A Perl egy olyan programozási nyelv, amelyet eredetileg arra találtak ki, hogy UNIX adminisztrációs feladatokat lehessen vele automatizálni, aztán egy kicsit kinőtte magát. Általában értelmezett (interpretált), de éppen napjainkban készül hozzá fordító program, amely C nyelvre fogja fordítani. Egyelőre maradjunk az értelmezett változatnál, és ebben gondolkodjunk. Ha eddig azt gondoltad, hogy a PASCAL a szépen és dokumentáltan programozható nyelv, és C-ben kegyetlenül olvashatatlan programokat lehet írni, akkor most értékeld át a dolgot: PASCAL-ban szépen formátumozott programokat lehet írni, C-ben olvashatatlan és Perl-ben kegyetlenül olvashatatlan programokat. Lehet. De nem kell. A nyelv neve egy rövidítés: Practical Extracting and Reporting Language, vagyis praktikus szerkesztő és jelentéskészítő nyelv. Eredetileg. De egyesek szerint ez csak azt fejezi ki, hogy mi volt a nyelv teremtőinek célja; az eredményt jobban kifejezi a Pathologically Eclectic and Rubbis Lister, ami magyarul csak annyit tesz, hogy betegesen túldíszített szemét listázó. Nos, mindenki eldöntheti, hogy melyik az saját szájízének megfelelő. Helló világ! Igen, ez a szokásos bevezető gyakorlat, amelyik semmi mást nem is csinál, mint kiírja a képernyőre, vagy a szabvány kimenetre, hogy Hello világ! Hát itt is van: print "Helló világ!\n"; És utána itt van az eredmény is: Helló világ! Persze ez nagyon egyszerű. A print beépített parancs kiírja az argumentumait a szabványos kimenetre. Aki programozott C-ben, annak ismerős lehet a \n karakter is, amelyik egy sort emel (újsor karakter). Félre a tréfával! Nézzünk valami komolyabbat! $a = 123; $b = 55; $c = $a + $b; $d = "kakukk\n"; $d = 'kakukk\n' if $c == 178; if( $d eq "kakukk\n" ){ print "Helló világ!\n"; }else{ print "Ma nincs jó napod!\n" } Itt mindjárt látunk is valamit. Például azt, hogy minden egyes változó neve előtt van egy dollár $ jel. Így nincs gond azzal, hogy egy név lefoglalt változó-e, vagy sem. Így lehet használni nyugodtan mindenféle változót, így akár a következőket is: $if $else $return $unless $while $or $and Ezek egyébként mind lefoglalt szavak lennének, ha lenne ilyen fogalom a Perl nyelvben. Az első három sor nem érdekes. A negyedik egy string értékadás, amelyik a $d változónak ad egy string értéket. Ez a string a k a k u k k karakterek és egy újsor karakter. A következő sorban levő utasítás először megvizsgálja, hogy a $c változó értéke 178-e. Rövid fejszámolás után kideríthetjük, hogy igen, bár az ilyen műveletek elvégzésére még a Perl is jobb nálam. A $d itt tehát új értéket kap. Ez az új érték azonban nem egyezik meg azzal, amit az előbb kapott (ennek nem is lenne semmi értelme, még egy ilyen
A Perl programozási nyelv – röviden
79/2
tanmesében sem). Az új érték a k a k u k k \ n karakterek, azaz nyolc karakter. Mitől? Miért fordított törtvonal, és n karakter van a füzér végén, és miért nem újsor karakter? A magyarázat az idézőjelek helyett használt aposztrófokban rejlik. Ha idézőjelet használunk, akkor a Perl értelmezi a stringet, az escape karaktereket éppen úgy, mint például a füzérben előforduló változókat (miket??? türelem!). Ha azonban aposztrófokat használunk, akkor mindez nem történik meg, a füzér úgy van, ahogy leírtuk, se több, se kevesebb. Na, haladjunk tovább. Ezek után már senkit sem lep meg, hogy amit kiír a program, az nem az előző "Hello világ!", hanem az, hogy Ma nincs jó napod! ami ugye nem igaz, mert máris rengeteg érdekes dolgot tanultál meg a Perl nyelvről. Ha részletesebben is érdekel a dolog, akkor visszamehetsz a nyitó oldalra, vagy innen is továbbléphetsz és olvashatsz a Perl változókról, a különböző program szerkezetekről vagy a stringekről, hogy csak néhányat említsünk azok közül, amik ebben az ízelítőben előjöttek. Perl változók A Perl nyelvben háromféle változó van: skalár ($) tömb (@), és hash (%) A változók nincsenek előre deklarálva, és bármelyik változó tárolhat füzért, egész számot, mutatót (ezek mind skalár értékek) akár ugyanaz a változó is egymás után hol ilyent, hol meg amolyant. Az is lehetséges, hogy egy tömb, vagy egy hash egyik eleme füzért, egy másik eleme számot egy harmadik meg akár mutatót tárol. Bármilyen alfanumerikus karaktersorozat lehet változónév, még kulcsszó is, mint a $if $else $return $unless $while $or $and mivel ezeket a Perl nem foglalja le magának. Amiket előre lefoglal, azok az olyan változók, mint a $/, vagy $, meg a társaik. Ezeknek speciális jelentésük van. Amivel leggyakrabban fogsz találkozni ezek közül az a $_, amelyik a default változó. (Egy csomó függvénynél, program szerkezetnél ha nincs megadva valamelyik szerepre változó, akkor a Perl a $_ változót használja.) A tömbváltozókat onnan lehet megismerni, hogy ezek előtt nem $ hanem @ jel van. Ezeknek is lehet értéket adni, de természetesen nem skalár, hanem tömb értéket, például: @tomb = (1, 2 , 3); Itt a @tomb egy tömbváltozó, amelynek van három eleme. Az egyes elemekre a PASCAL, vagy C nyelvben megszokott módon lehet hivatkozni a [ és ] zárójelek használatával. Viszont ilyenkor már egy elemre hivatkozunk, ami nem tömb, hanem skalár, tehát ilyenkor már a $ jelet kell a változó elé írni: $tomb[0] ami a @tomb tömbváltozó első elemét jelenti. (Hacsak a $[ változónak valahol nullától eltérő értéket nem adtunk.) A hash változó hasonlít a tömbhöz, de nem nullától n-ig megy az index, hanem bármilyen értéket felvehet. Lehet az index szám, string, mutató, vagy bármilyen más skalár érték. Amikor az egész hash változóra hivatkozunk, akkor % jelet írunk elé, amikor pedig az egyes elemeire, akkor $ jelet, mivel ilyenkor már egy eleme skalár érték. Az értékadás nagyon hasonló a tömb értékadáshoz:
A Perl programozási nyelv – röviden
79/3
%tomb = (1, 2 , 3 ,4 ); ami egy két elemű hash. Az egyik elem indexe 1, a másiké 3. Az egyik értéke 2, a másiké 4. Persze ez így elég olvashatatlan, és ezért a Perl nyelv nyújt egy sokkal olvashatóbb szintaxist is: %tomb = ( 1 => 2 , 3 => 4 , ); A hash egyes elemeire pedig úgy lehet hivatkozni, mint a tömb elemeire, de nem szögletes, hanem kapcsols zárójelet kell használni: $tomb{1} aminek az értéke a példánál maradva 2. És most tessék kapaszkodni, mert kihajolni veszélyes!! A következő változók mind használhatók egy programon belül: %valtozo $valtozo @valtozo És ezek mindegyike másik változó, sőt még ilyen nevű szubrutin is lehet! Ezek után nem lehetetlen a következő rövid program darab: %valtozo = ( 'alma' => 'gyimilcs', 'kutya' => 'allat', ); $valtozo = 3.14; @valtozo = (55,13,32); ami eddig mind más változónak adott értéket, de ezt még fokozhatjuk: $valtozo[4]=$valtozo; aminek a hatására a @valtozo tömb mérete automatikusan megnő, $valtozo[3] nem definiált értéket kap, $valtozo[4] viszont a Ludolf féle szám népszerű közelítő értékét kapja. Ezek után már senki sem csodálkozik azon, hogy a $valtozo=4; utasítás végrehajtása után akár a $valtozo{$valtozo}=$valtozo[$valtozo]; utasítás is kiadható.
Reguláris kifejezések, mintaillesztés
A Perl programozási nyelv – röviden
79/4
A Perl nyelv egyik, ha nem a legnagyobb erőssége az igen fejlett mintaillesztési lehetőség, vagy másképp fogalmazva a reguláris kifejezések kezelése. Persze a Perl nyelv előttjóval voltak már UNIX operációs rendszer alatt olyan eszközök, amelyek reguláris kifejezéseket használtak, de a Perl nyelvnél talán mindegyiknél jobb, és teljesebb lehetőségek vannak. Ha még nem használt soha reguláris kifejezéseket, akkor ennek a fejezetnek az elolvasása előtt ajánlott az m operátor illetve az s operátor fejezetek elolvasása. Ugyanakkor azok teljes megértéséhez szükséges ennek a fejezetnek az elolvasása. Így tehát nem tudom, hogy melyiket érdemes elolvasni először. Feltehetőleg az egyiket, aztán a másikat, és azután néhányszor újra. Bevezető Reguláris kifejezésre rendkívül egyszerű példát mutatni. A következő példa a @mail tömb elemeiről próbálja meg eldönteni, hogy jók lesznek-e eMail címnek. @mail = ( '
[email protected]', 'hab.akukk%mikkamakka@jeno', ); for( @mail ){ if( /^.*@\w+\..+$/ ){ print "$_ jó email címnek látszik\n"; }else{ print "$_ Ez nem jó cím\n"; } } Az első utasítás a @mail tömböt hozza létre. Ennek elemein megy végig a for ciklus, és minden egyes elemet megvizsgál, és megpróbálja eldönteni, hogy jó lesz-e elektronikus levélcímnek vagy sem. Mivela for ciklusnak nem adtunk meg változót, ezért a Perl a $_ változót használja ciklus változónak, és mivel az if utasításban sem adjuk meg, hogy mely változót akarjuk a reguláris kifejezéshez hasonlítani, ezért ez is ezt a változót használja. (Minő véletlen egybeesés.) A példabeli reguláris kifejezés szavakkal elmondva a következőt jelenti: a füzér kezdődjön ^ nulla vagy több bármilyen karakterrel .* utána következzen egy @ karakter majd legalább egy, vagy több betű \w+ majd egy pont \. végül még legalább egy vagy több bármilyen karakter .+ és legyen vége a füzérnek $. A kimenet:
[email protected] jó email címnek látszik hab.akukk%mikkamakka@jeno Ez nem jó cím A reguláris kifejezéseket, mint a fenti példában is látható használhatjuk arra, hogy bizonyos szintaktikus szabályoknak való megfelelést vizsgáljunk füzéreknél. Ehhez a m operátort használtuk a fenti példában. Magát az operátort azért nem kellett kiírni, mert a / jelet használtuk határolónak, a fűzért pedig azért nem, mert az a default változó, a $_ volt. Az if utasításbeli kifejezést írhattuk volna $_ =~ m/^.*@\w+\..+$/ alakban is. A másik lehetőség reguláris kifejezés használatára, amikor bizonyos részeket ki akarunk cserélni egy fűzérben. Nézzük példának a következő kis programot:
A Perl programozási nyelv – röviden
79/5
$text = 'Java szigetén nem használnak JavaScript programokat.'; $text =~ s/Java(?!Script)/Borneo/; print $text; aminek a kimenete Borneo szigetén nem használnak JavaScript programokat. Az s operátor egy reguláris kifejezést és egy interpolált füzért használ. Végignézi a változót, amely a példában $text és az első olyan részfüzért, amely megfelel a reguláris kifejezésnek kicseréli a második paraméterként megadott füzérre. Így lesz Java szigetéből Borneó. Érdemes megfigyelni, hogy ezeknél a műveleteknél nem = jelet használunk, hanem =~ operátort. Ezt pedig nem szabad összetéveszteni a ~= operátorral! (A nyelv szépségei!) Ha ugyanis valaki az előbbi példában a $text = s/Java(?!Script)/Borneó/; írná, akkor a helyettesítési operátor (s///) nem a $text változót, hanem a default $_ változót keresné, amelyben nem talána egyetlen Java alfüzért sem, és visszatérési értékként üres füzért ad vissza. Más szavakkal: a program nem írna ki semmit, vagy precízebben semmit írna ki. Részletesen és precízen az m operátorról, és a s operátorról. Ezeket egy kicsit nehéz megérteni a reguláris kifejezések ismerete nélkül, de vígasztaljon, hogy a reguláris kifejezéseket pedig nehéz megérteni az m és az s operátorok ismerete nélkül. Amikor a Perl egy füzért megpróbál hozzáilleszteni egy reguláris kifejezéshez mind a füzérben, mind pedig a reguláris kifejezésben balról jobbra halad, egészen addig, amíg el nem ér a reguláris kifejezés vagy a füzér végére. Ha ekkor az egész reguláris kifejezést hozzá tudta illeszteni a füzérhez, akkor a füzér megfelel a reguláris kifejezésnek, ha nem, akkor pedig nem. (Például az m operátor igaz, vagy hamis értéket ad vissza.) A meta karakter fogalma Az illesztés során a reguláris kifejezésben minden közönséges karakter, amelyik nem metakarakter (definíció mindjárt) önnmagának felel meg. Ha tehát a reguláris kifejezés következő karaktere egy 'a' betű, akkor a füzér következő illesztendő karaktere is 'a' betű kell, hogy legyen. A metakarakterek speciális karakterek, amelyek a reguláris kifejezésben speciális jelentőséggel bírnak. Ilyen például a . pont, amely a füzérben bármilyen nem újsor karakternek megfelel. Egy másik speciális karakter a $ jel, amelyik a füzér végének, vagy a füzér végén lévő újsor karakternek felel meg. Hasonlóan a ^ karakter a füzér elejének felel meg. Ezt a viselkedést mind az m, mind pedig az s operátoroknál változtatni lehet az m és s opciókkal. Az m opció esetén a füzért többsorosnak tekinti a rendszer, ami praktikusan annyit jelent, hogy minden sor végét meg lehet találni a $ jellel, ami a reguláris kifejezésben a sor vagy a füzér végét jelenti, és hasonlóan minden sor elejét a ^ jellel. Ennek az ellentéte a s opció, amely esetben a füzért egysorosnak tekinti a Perl, és a $ csak a füzér végét fogja megtalálni, vagy a füzér végén álló soremelést a ^ jel pedig csak a füzér elejét úgy, mintha sem az s sem pedig a m opciót nem adtuk volna meg. Az s opció igazi értelme, hogy ennek megadásakor a reguláris kifejezésekben a . pont karakter megfelel a soremelés karaktereknek is, míg enélkül az opció nélkül ezeknek a karaktereknek nem felel meg ez a metakarakter. Az egyik legfontosabb metakarakter a \ amelyet ha egy metakarakter elé írunk a füzérben a karakter pontosan önnmagának fog megfelelni, így \. egy pontot jelent a füzérben vagy \\ egy fordított törtvonal karaktert. Ha nem metakarakter elé írjuk a fordított törtvonalat, akkor előfordulhat hogy más jelentést kap a karakter, például \t a tabulátor, vagy \w az betű karaktereknek felel meg, de erről még később. Zárójelek
A Perl programozási nyelv – röviden
79/6
A zárójelek is speciális jelentéssel bírnak. Ezekkel a reguláris kifejezés egyes részeit lehet bezárójelezni, és ezekre a részekre lehet a későbbiekben hivatkozni a $1, $2, ... változókkal a reguláris kifejezésen kívül, vagy a \1, \2, ... referenciákkal a reguláris kifejezésen belül. Példaképpen $text = 'Java szigetén nem használnak szigonyt.'; $text =~ /(Ja(va)).*(szi).*\3(g(e|o))/; print "$1 $2 $3 $4 $5\n"; kimenete Java va szi go o Látható, hogy a számozási sorrend a nyitó zárójelek szerint megy, és nem a záró zárójelek szerint. Ennek csak abban az esetben van jelentősége, ha, mint ebben a példában, egymásba vannak ágyazva a zárójelek. Lehetőség van arra is, hogy úgy zárójelezzünk be egy részt a reguláris kifejezésből, hogy az ne hozzon létre referenciát. Ehhez a (?: nyitó karakter sort és a szokásos ) zárójelet kell használni, például: $text = 'Java szigetén nem használnak szigonyt.'; $text =~ /(Ja(?:va|vi)).*(szi).*\2(g(e|o))/; print "$1 $2 $3 $4\n"; kimenete Java szi go o Itt rögtön látunk egy új metakaraktert, a | jelet. Ez a jel választást jelent a bal és a jobb oldalán álló rész reguláris kifejezések közül bármelyik megfelelhet a füzér éppen soron levő darabjának. Karakter osztály Még egy érdekes zárójel van a reguláris kifejezésekben, a [ és ]. Ezek kartakter osztályokat fognak közre. Ha egy reguláris kifejezésben azt írjuk, hogy [acfer], akkor az az a, c, f, e és r betűk bármelyikének megfelel. Ugyanakkor rövidíthetünk is karakterosztályok megadásánál. Például [a-f] az összes a és f közötti karakternek felel meg, vagy [a-fA-F] ugyanez a karakter osztály, de a kisbetűk és a nagybetűk is. Ha a legelső karakter a karakterosztály megadásánál a [ karakter után egy ^ karakter, akkor a karakter osztály invertálódik, azaz [^a-f] bármilyen karakternek megfelel, kivéve az a és f közötti karaktereket. Karakterosztály megadásánál a | karakter is közönséges karakternek számít. Ismétlés Egy reguláris kifejezés egy részére, vagy az egész reguláris kifejezésre előírhatjuk, hogy hányszor kell egymás után alkalmazni. Ezt a reguláris kifejezések ismétlést előíró modosítóival tehetjük meg, amelyeket mindig a reguláris (rész)kifejezés után kell írni. Ezek: * nulla vagy többszöri ismétlés + egy, vagy többszöri ismétlés ? nulla, vagy egyszer {n} pontosan n-szer {n,} legalább n-szer {n,m} legalább n-szer, de legfeljebb m-szer Ha a kapcsos zárójel bármilyen más környezetben fordul elő, akkor normál karakterként értelmezi a Perl. n és m nulla és 65,535 közötti értékek lehetnek. Alaphelyzetben ezek az ismétlési módosítók falánkak, és annyira előreszaladnak, amennyire csak lehet. Ezt lehet visszafogni azzal, ha az ismétlési módosító mögé egy ? jelet írunk. Ekkor csak annyit ismételnek ezek a módosítók, amennyit feltétlenül kell. Példaképp egy reguláris kifejezés illesztés * és *? módosítóval 'Java szigetén nem használnak szigonyt.' =~ /Ja(.*)g(?:e|o)/; print "$1\n";
A Perl programozási nyelv – röviden
79/7
'Java szigetén nem használnak szigonyt.' =~ /Ja(.*?)g(?:e|o)/; print "$1\n"; és a kimenete va szigetén nem használnak szi va szi Speciális karakterek Mivel a reguláris kifejezések mint interpolált füzérek kerülnek kiértékelésre, ezért a következők is használhatók: \t tabulátor (HT, TAB) \n újsor, soremelés (LF, NL) \r kocsivissza karakter (CR) \f lapdobás (FF) \a csengő (bell) (BEL) \e escape (ESC) \033 oktális kód megadása (mint a PDP-11 nél) \x1B hexa karakter \c[ kontrol karakter \l a következőkarakter kisbetűsre konvertálva \u a következő karakter nagybetűsre konvertálva \L kisbetűsek a következő \E-ig \U nagybetűsek a következő \E-ig \E kisbetű, nagybetű módosítás vége \Q reguláris kifejezések meta karakterei elé fordított törtvonalat ra a következő \E-ig Ezeken kívül a Perl még a következőket is definiálja \w egy szóban használható karakter (alfanumerikus karakterek és aláhúzás) \W minden ami nem \w \s szóköz fajta karakter, szóköz, tabulátor, újsor stb. \S minden ami nem \s \d számjeg \D nem számjegy Ezek a jelölések karakterosztályok megadásában is használhatók, de nem intervallum egyik végén. A következők is használhatók még reguláris kifejezésekben: \b szó határának felel meg \B nem szó határnak felel meg \A csak a füzér elején \Z csak a füzér végén \G ott folytatja ahol az előző m//g abbahagyta A \b karakterosztályban használva visszalépés karakternek felel meg. Egyébként mint szóhatár olyan helyet jelöl, ahol az egyik karakter \w és a mellette levő \W. Ennek eldöntésére a füzér elején az első karakter elé és a füzér végén az utolsó karakter utánra egy-egy \W karaktert képzel a rendszer. A \A és \Z ugyanaz, mint a ^ és a $ azzal a különbséggel, hogy ezek még a m opció használata esetén sem felelnek meg a füzér belsejében levő soremelés karakternek. Egyéb kiterjesztések A reguláris kifejezések a Perl nyelvben a szokásos egyéb UNIX eszközökhöz képest további kiterjesztéseket is tartalmaznak. Így reguláris kifejezésen belül lehet használni (?#megjegyzés) megjegyzéseket lehet a reguláris kifejezésekben elhelyezni. Amennyiben az x opciót használjuk egy sima # is megteszi. (?:regexp) Zárójelezett reguláris kifejezés, amely azonban nem generál referenciát, azaz nem lehet rá hivatkozni a $1, $2, ... változókkal, illetve a \1,\2 ... visszahivatkozásokkal. Ugyanakkor nagyon hasznosak, akkor ha valamilyen alternatívát kell megadni a | metakarakterrel.
A Perl programozási nyelv – röviden
79/8
(?=regexp) Nulla hosszúságú előrenézés. Ezzel a konstrukcióval egy olyan rész reguláris kifejezést lehet megadni, amelyet a Perl leellenőriz, de mégsem vesz bele az illesztett listába. Például /\w+(?=\t)/ reguráris kifejezésnek egy olyan szó felel meg, amelyet egy tabulátor követ, a tabulátor azonban nem veszi figyelembe a Perl, csak megnézi, hogy ott van. Ha a helyettesítés operátort használjuk, akkor $t = 'jamaica rum rum kingston rum'; $t =~ s/([aeoui])(?=\w)/uc($1)/ge; print $t; kimenete jAmAIca rUm rUm kIngstOn rUm ami azt jelenti, hogy a mintaillesztés során a Perl megnézte, hogy betű áll-e a magánhangzó után, de azt a betűt, már nem tekintette az illesztett, és így helyettesítendő füzérdarab részének. Ennek megfelelően ez a kis programdarab minden olyan magánhangzót nagybetűre cserélt, amely nem szó végén állt. (?!regexp) Negatív nullahosszúságú előrenézés. Hasonló a (?= ... )-höz, de akkor fogadja el a mintát, ha a következő füzérdarab nem felel meg a megadott reguláris kifejezésnek. Az előző példát használva és persze módosítva egy kicsit $t = 'jamaica rum rum kingston rum'; $t =~ s/([aeoui])(?!\w)/uc($1)/ge; print $t; kimenete jamaicA rum rum kingston rum ami minden olyan magánhangzót cserél nagyra, amelyet nem betű követ. Nagyon fontos megjegyezni, hogy ezekkel a konstrukciókkal csak előre lehet nézni, visszafelé nem. Ha ugyanis azt írjuk, hogy (?!Borneo)Script, akkor az nem azt jelenti, hogy minden olyan Script amely előtt nem Borneo áll. Ez a reguláris kifejezés minden Script-et meg fog találni, a BorneoScript-eket is, illetve annak Script részét, hiszen amikor a (?!Borneo) részt értékeli ki a Perl azt fogja találni, hogy a vizsgált helyen nem Borneo áll, hanem Script. Ez így neki rendben van, megy tovább és ismételten látni fogja, hogy az adott helyen Script áll, ezt most már illeszti is a reguláris kifejezés további részéhez, hiába állt a Script előtt Borneo. (?imsx) Reguláris kifejezés értelmezését módosító opció megadása a reguláris kifejezésen belül. Ezeket az opciókat általában az m vagy s operátorok után szoktuk megadni, néha azonban szükség lehet, hogy magába a reguláris kifejezésbe kerüljön bele az opció. Ilyen lehet az, amikor a reguláris kifejezés egy változóban van megadva. Az egyéb opciók, mint az e vagy g nem adhatók meg a reguláris kifejezésen belül, hiszen ezek nem a reguláris kifejezésre vonatkoznak, hanem magára a m és s operátorok végrehajtására. Az opciókat érdemes a reguláris kifejezés elején megadni, mert különben igen érdekes, és meglehetősen nehezen értelmezhető hatásuk lesz, például a $t = 'jAmAIca rUm rUm kIngstOn rUm'; $t =~ s/(?i)ica/juli/g; $t =~ s/RuM(?i)/bor/; print $t; hatására miért csak az utolsó rUm-ból lesz bor: jAmAjuli rUm rUm kIngstOn bor Visszalépéses kiértékelés Amikor a Perl egy reguláris kifejezést illeszt egy füzérhez az illesztés csak akkor sikeres, ha az egész reguláris kifejezést sikerült illesztenie. Amikor az illesztés során a mintaillesztő algoritmus előre halad, és valahol elakad, akkor még nem adja fel, hanem megpróbál visszalépni és újra próbálkozik. Így, amikor a $text = 'Java szigetén nem használnak JavaScript programokat.'; $text =~ s/Java(?=Script)/Borneo/; print $text;
A Perl programozási nyelv – röviden
79/9
példában elindul a mintaillesztés a Perl eljut egészen az első Java végéig, és illeszti a reguláris kifejezést. Itt azonban elakad, mert a (?=Script) megkövetelné, hogy a Java szó után a Script szó következzen. Ezért visszalép és próbálja a füzér további részéhez illeszteni a reguláris kifejezést, amíg el nem jut a JavaScript szóhoz, amelyhez sikerül az illesztés, és ennek megfelelően megtörténik a csere, így az eredmény Java szigetén nem használnak BorneoScript programokat. Egy másik példát megnézve $t = 'Mi van a jing és a jang között? Talán a Jangce?'; $t =~ /jing(.*)jang/i; print $1; az eredmény és a jang között? Talán a Ennek az az oka, hogy amikor a jing szót megtalálja az illesztés a .* részkifejezésseé addig rohan előre, ameddig csak tud. Először a füzér végéig. Itt azonban elakad, és elkezd visszafelé lépkedni. Egészen a Jangce szóig, aholis sikeres a reguláris kifejezés maradék részének az illesztése is. Ismét egy példát nézve a $_ = "Van 1 számom: 53147"; if ( /(.*)(\d*)/ ) { print "Ami van: <$1>, a szám pedig <$2>.\n"; }else{ print "nincsen számom...\n"; } az eredménye Ami van:
, a szám pedig <>. aminek az oka, hogy a \d* hozzáilleszthető a füzér végén egy üres füzérhez. Helyesen: $_ = "Van 1 számom: 53147"; if ( /(.*\D)(\d+)/ ) { print "Ami van: <$1>, a szám pedig <$2>.\n"; }else{ print "nincsen számom...\n"; } az eredménye Ami van: , a szám pedig <53147>.
Az „m” operátor
A Perl programozási nyelv – röviden
79/10
Az m operátor a =~ vagy !~ operátorok valamelyike által megadott füzért hasonlítja össze a reguláris kifejezéssel. A visszatérési értéke skalár környezetben =~ használata esetén true, 1 ha a reguláris kifejezés megfelel a füzérnek, illetve false, '' ha a reguláris kifejezés nem felel meg a stringnek. !~ használata esetén fordítva. Ha nem adnak meg semmilyen füzért a =~ operátorral, akkor a default $_ változót használja a Perl. Az operátor általános alakja $text =~ m{regexp}gimosx ahol a gimosx karakterek bármelyike opcióként használható és az operátor működését befolyásolja a következőképpen: g globális, nem csak egyszeri keresés i kis és nagybetűk egyenértékűek m a füzért többsorosnak tekinti o a reguláris kifejezést csak egyszer értékeli ki a Perl s a füzért egysorosnak tekinti a Perl x kiterjesztett reguláris kifejezésként értelmezi a Perl a megadott reguláris kifejezést A határoló karakterek lehetnek bármilyen nem alfanumerikus, nem szóköz jellegű karakterek, ha / jelet használunk, akkor nem kell kiírni az m operátort. Ha olyan karaktert használunk határoló karakternek, amely zárójel jellegű, akkor annak párját kell használni a reguláris kifejezés lezárására. A reguláris kifejezést a Perl, mint interpolált füzért értelmezi és ha ennek kiértékelése üres füzért eredményez, akkor a legutoljára használt reguláris kifejezést használja a Perl. Ennek megfelelően a regexp tartalmazhat változókra való hivatkozást, de vigyázni kell, mert a például $/ könnyen úgy értelmezhető, mint a reguláris kifejezést lezáró per jel. Lista környezetben a visszatérési értéke egy olyan lista, amelynek elemei a kifejezésben bezárójelezett részek, például @k = "abbabaa" =~ m/(bb).+(a.)/; print $#k; print ' ',$k[0],' ',$k[1],"\n"; aminek kimenete 1 bb aa Ha nem volt sikeres a keresés, akkor üres listát ad vissza az operátor, ha pedig sikeres volt, de nem használtunk zárójeleket, akkor (1) értéket ad vissza. A opciók értelmezése hasonló, mint az s operátornál. A g opció használata esetén a nem csak egyszeri keresést több féle képpen is lehet értelmezni a környezettől függően. Lista környezetben addig keres, ameddig a füzér végére nem ér, és a bezárójelezett részeket rakja össze egy listába, például @k = "abbabaa" =~ m/(ab)(b|a)/g; print $#k; print ' ',$k[0],' ',$k[1],' ',$k[2],' ',$k[3],"\n"; aminek kimenete 3 ab b ab a
A Perl programozási nyelv – röviden
79/11
Skaláris környezetben a g módosító hatására minden egyes végrehajtásnál tovább keres az operátor és mindaddíg, amíg talál true értéket ad vissza, és amikor nem talál, akkor false értéket ad vissza, például $t = "abbabaa"; while( $t =~ m/(ab)(b|a)/g ){ print pos($t)," $1 $2\n"; } aminek kimenete 3 ab b 6 ab a Más szavakkal ilyen esetben az operátor megjegyzi, hogy hol tartott. Ezt a pozíciót egyébként a pos fügvénnyel le is lehet kérdezni. Az i opció megadása esetén a mintaillesztés során a kis és nagybetűket egyenértékűnek tekinti a nyelv. Ez alól kivételek az ékezetes magyar betűk, amelyeket a rendszer nem tekint betünek, csak akkor, ha a megfelelő POSIX setlocale fügvénnyel be lett állítva a nyelv. Az m opció esetén a füzért többsorosnak tekinti a rendszer, ami praktikusan annyit jelent, hogy minden sor végét meg lehet találni a $ jellel, ami a reguláris kifejezésben a sor vagy a füzér végét jelenti, és hasonlóan minden sor elejét a ^ jellel. Ennek az ellentéte a s opció, amely esetben a füzért egysorosnak tekinti a Perl, és a $ csak a füzér végét fogja megtalálni, vagy a füzér végén álló soremelést a ^ jel pedig csak a füzér elejét úgy, mintha sem az s sem pedig a m opciót nem adtuk volna meg. Az s opció igazi értelme, hogy ennek megadásakor a reguláris kifejezésekben a . pont karakter megfelel a soremelés karaktereknek is, míg enélkül az opció nélkül ezeknek a karaktereknek nem felel meg ez a metakarakter. Például $t = "allah\narab"; while( $t =~ /a(.)$/mg ){ print $1; }print "\n"; while( $t =~ /a(.)$/sg ){ print $1; }print "\n"; while( $t =~ /a(.)$/g ){ print $1; } kimenete hb b b Az o opció használata esetén a reguláris kifejezést csak egyszer értékeli ki a Perl futtató rendszer a script futása során, és ha szerepel benne olyan változó, amelynek az értéke a későbbiek során megváltozik, az nem fogja érdekelni a Perl-t. Például $t = "allah arab"; $a = 'allah'; $b = 'rab'; &q;&p; $b = 'szabad'; &q;&p; sub q { print ' q',$t =~ /$a\sa$b/o } sub p { print ' p',$t =~ /$a\sa$b/ }
A Perl programozási nyelv – röviden
79/12
kimenete q1 p1 q1 p Az x opció használatakor a Perl a reguláris kifejezést kiterjesztett értelemben használja, ami azt jelenti, hogy ilyenkor a szóközöket csak akkor veszi figyelembe ha azok előtt \ karakter van. Egyébként úgy tekinti, mint olyan karakter, amely arra való, hogy olvashatóbb legyen a program. Ebben az esetben a Perl megjegyzés karakterét a # karaktert is megjegyzés kezdetének tekinti a program, így az első példánkat írhatjuk @k = "abbabaa" =~ m/(bb) #két darab 'b' bekerül $1-be .+ #egy vagy több bármilyen karakter (a.) #egy 'a' betű és pontosan egy bármilyen karakter /x; #szóköz és megjegyzés engedélyezve print $#k; print ' ',$k[0],' ',$k[1],"\n"; alakban is. Ellenőrizzük, tényleg ugyanazt írta ki: 1 bb aa Ha a reguláris kifejezésen belül zárójeleket használunk, akkor a $1, $2 ... változók felveszik azoknaka részfüzéreknek az értékeit, amelyek a zárójelek között vannak. Ezek a $1, $2 ... változók a blokk végéig, vagy a következő reguláris kifejezés kiértékeléséig használhatók. Ajánlatos minnél előbb átmásolni őket. Ugyanezekre a részfüzérekre lehet hivatkozni már a reguláris kifejezésen belül is, amennyiben valamilyen ismétlődést akarunk megkövetelni, például $t = 'aegyabkettőbcháromc' ; while( $t =~ m/(a|b|c)(.*)\1/g ){ print "$2 "; }
aminek a kimenete egy kettő három Az „s” operátor Az s operátor a =~ vagy !~ operátorok valamelyike által megadott füzért hasonlítja össze a reguláris kifejezéssel és az első megtalált részfüzért kicseréli a megadott helyettesítő füzérrel. Az operátor általános alakja $text =~ s{regexp}{helyett}egimosx ahol a egimosx karakterek bármelyike opcióként használható és az operátor működését befolyásolja a következőképpen: e a helyett értéket kifejezésként értelmezi a program g globális, nem csak egyszeri keresés i kis és nagybetűk egyenértékűek m a füzért többsorosnak tekinti o a reguláris kifejezést csak egyszer értékeli ki a Perl s a füzért egysorosnak tekinti a Perl x kiterjesztett reguláris kifejezésként értelmezi a Perl a megadott reguláris kifejezést
A Perl programozási nyelv – röviden
79/13
Ha nem adnak meg semmilyen füzért a =~ vagy !~ operátorral, akkor a default $_ változót használja a Perl. A =~ vagy !~ operátorral megadott füzérnek balértéknek kell lennie, hiszen ezt a Perl módosítani akarja. A határoló karakterek lehetnek bármilyen nem alfanumerikus, nem szóköz jellegű karakterek. Ha ' karaktert használunk, akkor a Perl nem interpolált füzérként értelmezi a rguláris kifejezést illetve a helyettesítő füzért. (Kivéve ha az e opciót használjuk.) Határoló karakterként valamilyen zárójelet használva annak párját kell használni a reguláris kifejezés, vagy a helyettesítő füzér lezárására. Nem feltétlenül kell ugyanazt a karakterpárt használni a reguláris kifejezéshez és a helyettesítő füzérhez, de mind a kettőt külön be kell zárni, azaz s/alma/körte/ három határoló karaktert használ, de s(alma){korte} négy határoló karaktert használ. Ha a reguláris kifejezés üres füzér, akkor a legutoljára használt reguláris kifejezést használja a Perl. Az operátor visszatérési értéke a sikeresen elvégzett cserék száma, illetve ha nem sikerült egyetlen cserét sem elvégeznie akkor false, '' üres füzér, illetve a !~ használata esetén ennek ellentéte. Precízebben ($x !~ ...) ugyanaz, mint (! $x =~ ...). A opciók értelmezése hasonló, mint az m operátornál. Az e opció esetén a program a helyettesítő füzért, mint kifejezést értékeli ki, és ennek eredményét használja a helyettesítéshez. Ez egy teljes Perl kiértékeléást jelent, úgy, mint az eval függvény használatánál, de a szintaktikus elemzés és ellenőrzés fordítási időben történik. A g opciónál a cseréket addig folytatja, amíg végig nem ér a füzéren, azaz $t = "abbab" ; $t =~ s/ab/aa/g; print $t; aminek a kimenete aabaa Ebből az is látszik, hogy a továbbkeresést onnan folytatja ahol az előző csere végetért, azaz a helyettesítésként berakott füzért már nem bántja. Ha nem használjuk a g opciót, akkor az operátor emlékszik arra, hogy hol fejezte be az előző cserét, és onnan folytatja. Ezzel lehetővé válik, hogy egy ciklussal ugyanazt a hatást érjük el, mint a g opcióval, de közben minden egyes csere után még a ciklus törzse is végrehajtódik: $t = 'bababababababab' ; $s = 'bab'; $r = 'bib'; while( $t =~ s/$s(.)/$r$1/ ){ print $1; } print "\n$t\n"; aminek a kimenete aaaaaa
A Perl programozási nyelv – röviden
79/14
bibibibibibibab Ha pedig a pos függvényt is bevetjük, akkor elérhetjük, hogy azokat a helyettesítő füzéreket is figyelembe veszi az operátor, amelyeket az előző csere alkalmával helyezett el a füzérben: $t = 'bababababababab' ; $T = $t; $s = 'bab'; $r = 'bib'; $T =~ s/$s/$r/g; while( $t =~ s/$s/$r/ ){ pos($t) -= length($r); } print "$T\n$t\n"; aminek a kimenete bibabibabibabib bibibibibibibib Az i opció megadása esetén a mintaillesztés során a kis és nagybetűket egyenértékűnek tekinti a nyelv. Ez alól kivételek az ékezetes magyar betűk, amelyeket a rendszer nem tekint betünek, csak akkor, ha a megfelelő POSIX setlocale fügvénnyel be lett állítva a nyelv. Az m opció esetén a füzért többsorosnak tekinti a rendszer, ami praktikusan annyit jelent, hogy minden sor végét meg lehet találni a $ jellel, ami a reguláris kifejezésben a sor vagy a füzér végét jelenti, és hasonlóan minden sor elejét a ^ jellel. Ennek az ellentéte a s opció, amely esetben a füzért egysorosnak tekinti a Perl, és a $ csak a füzér végét fogja megtalálni, vagy a füzér végén álló soremelést a ^ jel pedig csak a füzér elejét úgy, mintha sem az s sem pedig a m opciót nem adtuk volna meg. Az s opció igazi értelme, hogy ennek megadásakor a reguláris kifejezésekben a . pont karakter megfelel a soremelés karaktereknek is, míg enélkül az opció nélkül ezeknek a karaktereknek nem felel meg ez a metakarakter. Példát az m operátornál mutatunk. Az o opció használata esetén a reguláris kifejezést csak egyszer értékeli ki a Perl futtató rendszer a script futása során, és ha szerepel benne olyan változó, amelynek az értéke a későbbiek során megváltozik, az nem fogja érdekelni a Perl-t. Példát az m operátornál mutatunk. Az x opció használatakor a Perl a reguláris kifejezést kiterjesztett értelemben használja, ami azt jelenti, hogy ilyenkor a szóközöket csak akkor veszi figyelembe ha azok előtt \ karakter van. Egyébként úgy tekinti, mint olyan karakter, amely arra való, hogy olvashatóbb legyen a program. Ebben az esetben a Perl megjegyzés karakterét a # karaktert is megjegyzés kezdetének tekinti a program. Példát az m operátornál mutatunk. Ha a reguláris kifejezésen belül zárójeleket használunk, akkor a $1, $2 ... változók felveszik azoknaka részfüzéreknek az értékeit, amelyek a zárójelek között vannak. Ezek a $1, $2 ... változók a blokk végéig, vagy a következő reguláris kifejezés kiértékeléséig használhatók. Ajánlatos minnél előbb átmásolni őket. Ezeket a változókat lehet használni a helyettesítő füzérben is. Ugyanezekre a részfüzérekre lehet hivatkozni már a reguláris kifejezésen belül is, amennyiben valamilyen ismétlődést akarunk megkövetelni, például $t = 'aegyabkettőbcháromc' ; $i = 1; $i++ while $t =~ s/(a|b|c)(.*)\1/$i/ ; print "$t\n";
A Perl programozási nyelv – röviden
79/15
aminek a kimenete 123 Mutatók Perlben minden olyan változó, amely valamilyen skalár, tehát szám, fűzér stb. értéket tartalmazhat; tartalmazhat mutatót is, vagy Perl terminológiával referenciát. A Perl nyelv kétféle referenciát ismer: puha és kemény referenciát. A puha referencia a változók nevén keresztül éri el a tárolt értéket, míg a kemény referencia a változó helyére mutat. Nézzünk egy egyszerű példát: $alma = 113; $korte = 'alma'; $szilva = \$alma; print "$$korte = $$szilva\n"; És az eredményt: 113 = 113 ami egy nagy igazság. Körte egy füzért tartalmaz, és amikor a Perl értelmező a $$körte kifejezést megtalálja, akkor ebből először $alma-t csinál, majd 113-at. A $szilva változó esetében más a helyzet. Itt a $$szilva kifejezés megtalálásakor a Perl interpreter kiértékeli a $szilva változót, amely egy mutató, amely az $alma változó tartalmára mutat. Látható, hogy mind a két esetben a referencia használatához a $ jelet kellett a referencia érték elé írni. A mutató létrehozásakor a változó neve elé egy \ jelet írtunk. Nagyon kényelmes a Perl a memóriakezeléssel kapcsolatban. Nem kell mindenféle malloc, alloc és hasonló függvényeket hívnunk, és nem kell free jellegű memória felszabadító fügvényekkel sem bíbelődnünk. A Perl mindig tudja, hogy mi az amit még használunk, és mi az amit nem. Így akár azt is megtehetjük, hogy $alma = 114; sub pointir { my $alma = 113; return \$alma; } $korte = 'alma'; $szilva = &pointir; print "$$korte = $$szilva\n"; egy helyi változóra mutató mutatót adunk vissza értékül (C-nél ez teljesen helytelen, és szerencsés esetben core dump a jutalom). A Perl tudja, hogy a létrehozott lokális változóra van hivatkozás és megtartja mindaddig, amíg valamilyen változón keresztül elérhető. Így az eredmény: 114 = 113 Hát ez nem igaz! Precízebben fogalmazva a lokális változót nem tartja meg a Perl, csak azt a memória helyet, ahol tárolja. Így sub pointir { my $alma = 113; return \$alma; }
A Perl programozási nyelv – röviden
79/16
$korte = &pointir; $szilva = &pointir; $$szilva++; print "$$korte < $$szilva\n"; eredménye 113 < 114 Persze nem csak egyszerű változókra lehet mutogatni, ennek nem is lenne sok értelme, hanem tömbökre, hash változókra, függvényekre, meg objektumokra. Nézzünk egy komplex példát, amiben van minden: $alma = sub { my @alma = (1,1,3); return \@alma; }; $dinnye = sub { my %alma = (0,1,1,1,2,3); return \%alma; }; $korte = &$alma; $szilva = &$dinnye; $$korte[2]++; $korte->[2]--; $$szilva{2}++; $szilva->{2}--; for $i (0 .. 2){ print $$korte[$i] } print ' = '; for $i (0 .. 2){ print $$szilva{$i} } aminek eredménye 113 = 113 (Ki gondolta volna!) A példában $alma és $dinnye két függvényre mutató változó. Az egyik egy tömbre, a másik egy hash-ra mutató mutatót ad vissza értékként. Mind a kettő elérhető a már megismert módon a két $$ használatával is, de elérhetők a tömb, és a hash egyes elemei a C nyelvben megszokott -> operátorral is. Program szerkezetek A Perl az utasításokat egymás után hajtja végre, úgy mint C nyelvben. Végül is nem ez az egyetlen hasonlóság. Az utasításokat általában pontosvessző zárja le, de nem feltétlenül kell, ez elhagyható egy blokk utolsó utasításánál. Majdnem elfelejtettem. Egy program blokk, azaz utasítások egy csoportja { és } között van. Ez kívülről úgy tekinthető, mint egy utasítás. Belül lehetnek utasítások, lokális változók. Viszont van if, while, do, unless. Röviden: if( kifejezés ) blokk vagy if( kifejezés ) blokk else blokk
A Perl programozási nyelv – röviden
79/17
És már most érdemes észrevenni, hogy nem utasítás, hanem blokk szerepel itt is és más szerkezetekben is, azaz szintaktikusan hibás a if( $bela eq '3' ) $geza= 2 else $juli=4 szerkezet. Ehelyett a if( $bela eq '3' ){ $geza= 2 }else{ $juli=4 } használandó. És ez nagyon, nagyon jó. Vagy nem. Szóval attól függ, hogy a C vagy a PASCAL lelkület bújik elő belőled. Rossz, mert eszelősen sokat kell gépelni (amíg meg nem tanulod, hogy lehet utasítás if kifejezés alakban is használni), viszont baromi jó, mert nincs vele gond, hogy kell, vagy nem kell, szabad vagy nem szabad az else előtt pontosvesszőt használni, és akkor az az else most melyik if-hez tartozik? if ! kifejezés helyett használható unless kifejezés . Lassulunk, pörgessük fel! Ciklusok: while( kifejezés ) blokk elején tesztel, és ami a végén tesztel: do blokk while( kifejezés ) Nincs until! Viszont van for minden mennyiségben: for( kif1 ; kif2 ; kif3 ) blokk pontosan úgy, mint C-ben, de van itt valami jobb is: for $valtozo ( lista ) blokk Ez a ciklus végigmegy a lista összes elemén, és $valtozo minden egyes ciklus lefutásra az aktuális lista elem. Erre az időre ez a változó lokális, utána ugyanaz az értéke, mint ami előtte volt. Ebbe beleértendő az is, ha az értéke undef volt. Egy ciklusból ki lehet jönni előbb is, mint ahogy az véget érne. Ha valahol a ciklus belsejében végrehajtódik egy last utasítás, akkor a ciklus befejeződik. (Hé, C programozók! Nem emlékeztet ez valami break nevü valamire?) Ha egy ciklus előtt egy cimke van, akkor a last utasításban erre lehet hivatkozni, és akkor nem feltétlenül a legbelső ciklus futása szakad csak meg, hanem a körülötte levőké is, egészen a cimkézett ciklusig. Ehhez hasonlóan létezik egy olyan utasítás, amelyik újrakezdi a ciklust. Ezt a Perl next-nek hívja. (Hopp! Hopp! Rémlik valami continue?) Természetesen itt is meg lehet adni cimkét.
A Perl programozási nyelv – röviden
79/18
És most jön valami érdekes: a ciklus után meg lehet adni egy continue blokkot, amelyiket akkor végrehajtódik, ha a ciklusban egy next utasítást hajtottunk végre. Viszont van egy redo utasítás, amelyik még ezt is kikerüli, és így indítja újra a ciklust. Most már elég sokat dumáltunk, lássunk egy példát: $i = 0; while( $i < 7 ){ $i ++; print "start $i\n"; next if $i == 1; redo if $i == 2; last if $i == 4; print "end $i\n"; }continue{ print "$i countinue\n"; } és amit kiír: start 1 1 countinue start 2 start 3 end 3 3 countinue start 4 Biztos, hogy ezt írja ki, mert ezt a jegyzetet nem tiszta HTML-ben írom, hanem először átengedem egy (természetesen Perl-ben írt) makro preprocesszoron, amelyik többek között berakja a szövegbe a programot, meg amit kiírt azt is. Emberi hiba kizurvu. Van goto utasítás is a nyelvben. Méghozzá nem is akármilyen. Ha valaki akarja, akkor használhatja a szokásos goto CIMKE alakot, de mivel a nyelv teljesen interpretált, ezért a CIMKE helyén szerepelhet bármilyen kifejezés, amelyik egy címke nevét adja meg. (Ez például erősen megnehezíti azok dolgát, akik fordítót írnak a nyelvhez.) Ha valakinek még ez sem elegendően perverz, akkor használható a goto &NAME alak, amelyik a NAME szubrutint hívja meg, de úgy, hogy onnan már nem ide, hanem a goto utasítást tartalmazó szubrutint meghívó függvénybe tér vissza a vezérlés. (Ha még nem jutottál el odáig, akkor csak annyit, hogy a szubrutinokat a &NAME alakban kell meghívni.) Nézzünk egy goto példát: goto LABEL1; print "Ezt nem írom ki\n."; LABEL1: print "Ezt kiírom.\n"; $i = 2; goto ['LABEL00','LABEL10','LABEL20','LABEL30']->[$i]; LABEL00: print 'LABEL00'; goto ENDE; LABEL10: print 'LABEL10'; goto ENDE; LABEL20: print 'LABEL20'; goto ENDE; LABEL30: print 'LABEL30'; goto ENDE; ENDE:; &sub1; &sub2;
A Perl programozási nyelv – röviden
79/19
sub sub1 { print "\nsub1\n"; goto &sub2; } sub sub2 { my @c = caller(); print " @c sub2\n"; } és amit kiír: Ezt kiírom. LABEL20 sub1 main gototest.pl 12 sub2 main gototest.pl 13 sub2 Szubrutinok Perl-ben nagyon egyszerű szubrutint írni: sub alma { print "Bent vagyok a szubrutinban!!!"; return; } A szubrutinból kijönni a return utasítással lehet éppen úgy, mint C-ben, de ez el is hagyható. A return után lehet írni a visszatérési értéket. Ugyanúgy, mint C-ben egy szubrutinnak mindig van értéke, legfeljebb nem használjuk. Lehet, hogy jobb lenne func-nak hívni, de a Perl sub-nak hívja. Egy szubrutint úgy lehet meghívni, hogy a neve elé az & jelet írjuk. Meg lehet hívni úgy is, hogy nem írjuk oda az & jelet, de ez nem mindig működik. A függvényeknek paramétert is lehet adni. A paramétereket ugyanúgy, mint a normális programozási nyelveknél a függvényhívás után kell vesszővel elválasztva írni, zárójelek között. Ezek a @_ tömbbe kerülnek bele, és így a $_[x] formában lehet rájuk hivatkozni. &ssss(1,2,3); sub ssss { print $_[0],$_[2],$_[3],"\n"; } ssss(1,2,3); A függvényeken belül hivatkozhatók a globális változók, de hivatkozhatók lokális változók is. Ezekből pedig kétféle lehet. Az egyik a függvényen belül helyileg lokális, a másik pedig időben, a függvény futási ideje alatt lokális. Nem világos? Nézzünk egy példát: $my = 'global'; $local = 'global'; &subi; &bubi; sub subi { my $my ='my'; local $local = 'local'; &bubi;
A Perl programozási nyelv – röviden
79/20
} sub bubi { print "$my\n$local\n"; } és amit kiír: global local global global Amikor bubi először lefut $local lokális, a $my változóhoz azonban, mint globális változóhoz fér hozzá, a subi függvény $my nevü változójához nem fér hozzá. A my deklarációval létrehozott változók, tehát úgy lokálisak, mint ahogy azt megszoktuk a normális programozási nyelvek esetében, a local viszont inkább úgy viselkedik, mint aki a globális változó értékét félreteszi, majd amikor lefutott a félretett értéket visszarakja. Nézzünk most ismét egy példát: print &suba(100); sub suba { my $i = shift; if( $i%2 ){ $i+1 }else{ $i-1 } } és amit kiír: 99 Itt két dolgot érdemes megfigyelni. Az egyik, hogy egy lokális változóba, egy shift operátorral, amelyiknek a default argumentuma a @_ tömb, kivesszük a szubrutin argumentumát. Ezzel hasonló formában lehet az argumentumokat kezelni, mint normális nyelveknél. Perlsze lehet Perlkedni, akinek kedve van, de az ember egy idő után lenyugszik, főleg ha nem csak játszik, hanem méretes programokat gyárt. A másik dolog, hogy elhagytuk a return utasítást. Egy szubrutin értéke megegyezik az utoljára végrehajtott utasítás értékével. Ha ez egy return utasítás, akkor a return után írt kifejezés értéke a visszatérési érték. Fájl kezelés A fájlkezelés az egyik legegyszerűbb dolog a Perl nyelvben. Mivel ez egy olyan terület, amelyik minden programban előfordul, és mivel a Perl elsősorban a UNIX operációs rendszerhez lett kitalálva, ahol a fájl alapfogalom, ezért nem csak könyvtári függvények, hanem programszerkezetek is rendelkezésre állnak a fájlok kezelésére. A legegyszerűbb fájlkezelő utasítás, amellyel korábbi példákban is már találkoznod kellett a print. Ez az utasítás, vagy ha úgy tetszik beépített függvény egy fájlba, vagy a szabványos kimenetre írja ki a paraméterként megadott értékeket. A paraméterek lehetnek sztringek, valós vagy egész számok, változók, amelyek ilyen értékeket tartalmaznak, de lehetnek mutatók, vagy nem skalár értékek is. Ez utóbbi esetben a print utasítás valamilyen olyan karakter alakban írja ki a változó, vagy kifejezés értékét, hogy az legalább hibakeresési célra használható legyen.
Nézzünk egy egyszerű példát:
A Perl programozási nyelv – röviden
79/21
$a = 1; $b= 'alma\n'; $c = "alma\n"; $d = \$c; print $a,$b,$c,$d; és az eredményt: 1alma\nalma SCALAR(0xcb7468) Látszik, hogy $a értéke 1, $b értéke az aposztróf használata miatt nem lett kifejtve, és emiatt nem újsor karakter van a végén, hanem egy \ és egy n betű, de $c végén már valóban van egy soremelés. $d egy mutató, amelyik a $c változóra mutat, és ennek nyomtatott képe a SCALAR(xxx). A konkrét érték minden egyes futtatásnál más lehet, attól függően, hogy $c hova kerül a memóriában. A print utasítás egyes paramétereit vesszőkkel választottuk el, azonban nagyon gyakran úgy akarunk kiíratni változó értékeket, hogy közbe mindenféle apróbb füzéreket helyezzük el. Például (ez a program az f2.pl fájlban van): $a=3;$b=55; print "A értéke=",$a," B értéke=",$b,"\n"; Ennek kimenete: A értéke=3 B értéke=55 Aki azonban ezt a print utasítást leírta az nagyon nem Perl fejjel gondolkozott. Az IGAZI Perl programozó ilyenkor a következő sorokat írja (ez a program az f3.pl fájlban van): $a=3;$b=55; print "A értéke=$a B értéke=$b\n"; aminek kimenete A értéke=3 B értéke=55 Ha ez nem ugyanaz, mint az előbb, akkor elrontottam a példát. (A példákat és a kiírt eredményeket a HTML fájlba egy Perl program állítja elő, így kizárt, hogy el legyen írva. Na jó: kevéssé valószínű.) Természetesen nem csak a szabványos kimenetre lehet írni, hanem bármilyen fájlba, amelyiket írásra megnyitott a program. A fájlok megnyitására az open utasítás szolgál, a fájlok bezárására pedig a close. Nézzünk egy példát: open(F,"f3.bak"); while( $line = ){ $line =~ s/",//g; $line =~ s/,"//g; print G $line; } close G; close F; Ez a kis program beolvassa az egyik fenti példaprogramot, és kiírja a f3.bak fájlba azt a verziót, amelyre azt mondtuk, hogy azt egy IGAZI Perl programozó készítette. Egy kicsit lehet ebből a példából tanulni a reguláris kifejezéseket is, de most nem ez a lényeg. Figyeljünk arra, hogy hogyan nyitottuk meg a fájlt, hogyan írtunk bele, hogyan olvastunk belőle, és hogyan zártuk le.
A Perl programozási nyelv – röviden
79/22
Az első dolog amit megfigyelhetünk, az az, hogy a fájlokat nem változókkal azonosítjuk, hanem handlerekkel (ki tudja a hivatalos terminológiát erre a szóra? fogantyú?). Ez azt jelenti, hogy a fájl azonosító elé nem írunk $ jelet, és általában nagybetűt szoktunk használni a fájlazonosításra a programon belül, de ez csak konvenció, nem kötelező. A másik dolog, amit meg lehet figyelni, hogy az open utasítás második argumentuma nem egyszerűen a fájl neve, hanem egy olyan füzér, amely tartalmazza a fájl nevét, de azt is, hogy a fájlt hogyan akarjuk megnyitni: írásra, olvasásra, vagy mindkettőre (ez utóbbira az előző példában nincs minta, majd még lesz). Ha az open utasításban a második argumentumban a fájl neve előtt nincsen semmilyen jel, akkor a fájlt olvasásra nyitjuk meg. Ha < jel van a fájlnév előtt, az ugyanaz, mintha nem használtunk volna semmilyen jelet. Általában szokás ezt használni, annak ellenére, hogy ez a default, mert olvashatóbbá teszi a programot. Ha a fájl neve előtt > jel van, akkor írásra nyitottuk meg a fájlt. Ha a fájl neve előtt <jel van, akkor olvasásra. Ezen kívül még használható a >> jel a fájlhoz való hozzáírásra, a +< a fájl írására és olvasására. Erre használható a +> jel is, ez azonban megnyitáskor törli a fájlt. A fájlműveletek mindig a fájl aktuális pozíciójára vonatkoznak, amelyet egy fájl foganytű (handle) tartalmaz. Amikor kiírunk valamit, akkor oda íródik a szöveg ahova a foganyú mutató mutat, és ezután a fogantyú mutató a kiírt szöveg utánra fog mutatni. Amikor beolvasunk valamit egy fájlból, akkor onnan történik az olvasás ahova a fogantyú mutató mutat, majd az olvasás után a fogntyú motató a beolvasott adatok utánra fog mutatni. Ez olyan, mint más nyelveknél. Egy fájlból olvasni a alakban lehet, ahol a kisebb és a nagyobb jelek közé kell írni a fájlkezelőt. Ez az utasítás skalár környezetben egy rekordot olvas be, lista környezetben pedig a hátralevő rekordok listáját. Egy rekord általában egy sor, mivel a rekord határoló karakter $/-ben megadva LF, de ha $/nek más értéket adunk, akkor a beolvasás is másképp hajtódik végre. A végletekig elmenve ha a $/ változónak undef értéket adunk, akkor egész fájlokat tudunk változóba nagyon gyorsan beolvasni. Ha egy fájlon belül akarjuk mozgatni a fogantyú mutatót, akkor erre a legegyszerűbb módszer a seek függvény meghívása. Ennek formája: seek FILEFOGÓ,POZÍCIÓ,HONNAN A FILEFOGÓ a fájlkezelő, a POZÍCIÓ az a hely ahova állítani szeretnénk a mutatót, a HONNAN paraméter pedig lehet 0, 1 vagy 2. Ha HONNAN 0 akkor a fájlon belül POZÍCIÓ a fájl elejétől számít. Ha HONNAN egy, akkor a mutató pillanatnyi pozíciójához képest fog elmozdulni, ha pedig 2, akkor a fájl végétől számítva. Általában ajánlatos ezt a függvényt meghívni minden olvasási és írási művelet között. Ennek az oka nem a Perl nyelvben keresendő, hanem azokban a könyvtári függvényekben, amelyeket az operációs rendszer biztosít a Perl programok számára. A seek meghívásának a hatására a kiírandó adatok kikerülnek a pufferből, míg egy olvasás utáni írásnál egyes operációs rendszereken nem. Ha azt akarjuk megtudni, hogy a fájlfogantyú mutatója éppen hova mutat, akkor a tell függvényt hívhatjuk meg. Argumentuma a fájlfogantyú, ha nem adunk meg argumentumot, akkor az utoljára olvasott fájlt fogja használni. Egy fájl hosszát le lehet rövidíteni a truncate függvénnyel. Ennek két argumentuma van: a fájlfogantyú, és a megkívánt hossz. Amikor egy fájlba írunk, vagy olvasunk onnan, akkor előfordulhat, hogy más is hozzá akar férni a fájlhoz. Ez pedig gondot okozhat, ha egyszerre több processz is ír a fájlba. Ha tehát egy fájlt le akarunk foglalni, akkor a flock függvényt kell használni. Ennek két argumentumot kell megadni. Az első a fájlfogantyú, a másodika lezárás módja:
A Perl programozási nyelv – röviden
79/23
1 ?? 2 egyedi lezárás, más nem férhet hozzá a fájlhoz 4 ?? 8 lezárás megszüntetése. A flock függvény addig fog várni, amíg hozzá nem lehet a megfelelő módon férni a fájlhoz. Fontos, hogy eközben a fájlmutató értéke nem változik. Ha például egy fájlhoz hozzá akarunk írni, vagyis a >> jelet használtuk a fájl megnyitására, majd ezután a megnyitott fájlt megpróbáljuk lezárni flock függvénnyel, akkor ezután egy seek F,2 függvényhívást is meg kell ejtenünk, hogy a fájlmutató a fájl végére mutasson. A fájlokat kezelő függvényeknél általában nem csak egy fájlfogantyú nevet lehet megadni, hanem használni lehet ehelyett változót, amelynek értéke a fájlfogantyú neve. Ez alól Win32 környezetben egyes Perl verziók kivételek, ahol a truncate függvény hibás, és emiatt itt csak kerülő út alkalmazható. Vannak még más fájlkezelő függvények is, ezekről részletesen a itt. Füzérek A füzérek, vagy sztringek igen gyakran előfordulnak a Perl programokban. Ennek az alapvető oka, hogy a Perl eredetileg UNIX rendszeradminisztrációs feladatok automatizálására találták ki, és mivel a UNIX a rossz nyelvek szerint nem más, mint szövegfájlok halmaza, ezért természetes, hogy a füzérek kezelése igen erős a Perl nyelvben. A füzérek ugyanolyan skalár értékek, mint az egész vagy a valós számok. A program szövegében előfordulnak számos helyen, általában ' vagy " jelek között, vagy néhány esetben akár még anélkül is. Az alapvető különbség az aposztróf és az idézőjel használata között, hogy az aposztrófok között leírt füzér az amit leírtunk, minden egyes karakter, ahogy szerepel, míg az idézőjelek használatánál a Perl részben értelmezi a füzért (interpolált füzér). A következő kis program $a = 'alma'; print "$a\n"; print '$a\n'; kimenete alma $a\n amiből rögtön két dolog is látszik: Az interpolált füzéren belül nem csak a speciális karaktereket, mint az újsor karakter értelmezi a Perl, hanem a változóneveket is kifejti. A nem interpolált füzérekben viszont még a fordított törtvonalat is közönséges karakternek tekinti a nyelv. Nézzünk egy összetettebb példát: $alma = 'kurta'; $korte[3] = 4; $szilva = [ 13, 55, 33]; $szolo{ringlo} = 'hosszi'; $dinnye = { birka=>'emloves', csirke=>'mador', ponty=>'hallo'}; sub barack { return 'narancs' } print "1=$alma $korte[3] $szilva->[0]\n"; print "2=$$szilva[1] $dinnye->{csirke} $$dinnye{ponty}\n"; print "3=@$szilva\n"; print "4=&barack\n"; aminek kimenete
A Perl programozási nyelv – röviden
79/24
1=kurta 4 13 2=55 mador hallo 3=13 55 33 4=&barack Ebből az látszik, hogy nagyon sok mindent értelmez a nyelv az interpolált füzérekben, de nem mindent. Például nem hív meg szubrutint. A füzérekkel kapcsolatban mindenképpen érdemes megjegyezni azt, hogy a Perl számára A füzér nem egy karaktertömb, mint a C számára, hanem egy bájtsor. Ennek következménye, hogy a Perl nem null karakterrel zárja le füzéreket, hanem tárolja minden egyes füzér hosszát. Emiatt a null karakter, éppen úgy, mint bármilyen más bájtérték része lehet egy füzérnek. Modulok A Perl nyelv lehetőséget ad arra, hogy az egyes funkciókat modulokba gyűjtsük, és ezeket a modulokat felhasználjuk más programokban. Ez gyakorlatilag annyit jelent, hogy a modulok változói más szimbólumtáblában kerülnek elhelyezésre, és így bármiképpen is lettek elnevezve, nem zavarják más programrészek változóit. A modulok változóit, szubrutinjait természetesen kívülről is el lehet érni, és használni. Ebben az esetben a $modul::változó alakot kell használni. Egy modul definícióját mindig a package kulcsszó vezeti be, amelyet a modul neve követ. Az alapmodul, amelyet eddig is ismertél a main, amely a változók és függvények neve elől akár el is hagyható, így $v, $::v és $main::v ugyanazt a változót jelölik. Modulok egymáson belül is elhelyezkedhetnek, ebben az esetben a külső és a belső modul nevét is meg kell adni: $kulso::belso::valtozo. Nézzünk meg egy egyszerű példát: $barack = &gyimilcs::kukac; print "$barack, $gyimilcs::barack\n"; exit; package gyimilcs; sub kukac { $barack = 'repa'; 'karotta' } amelynek kimenete: karotta, repa A példaprogram a gyimilcs modul kukac szubrutinját hívja meg, amely a modul $barack változójának értékét beállítja, ugyanakkor a visszatérési érték a main modul azonos nevű változójába kerül. Amikor egy modult használunk, akkor általában jó, ha a modul külön fájlban van. No nem azért, mert a modulnak külön fájlban kell lennie, de nagyon gyakran előfordul, hogy egy modult az egyik ember megírja, és nagyon sokan meg használják. Ha ilyenkor mindenki beszerkesztené a modult a saját programjába, akkor meglehetősen nagy forrásprogramok keletkeznének, és az egész nagyon áttekinthetetlen lenne. Ha egy modul egy külön fájlban van, akkor külön meg kell mondani a Perl értelmezőnek, hogy a modult használni akarjuk. Erre a use kulcsszó való. Ez után kell megadni a modul fájlnak a nevét, amely ugyan az, mint a modul neve, ami a package kulcsszó után áll. A fájl kiterjesztése .pm, de ezt NEM írjuk a use kulcsszó után.
A Perl programozási nyelv – röviden
79/25
Ha van egy egyszerű modulunk például a modul1.pm fájlban, és ezt használni szeretnénk a prog.pl fájlból, akkor ezt a következő módon tehetjük meg: push @INC, '.'; use modul1; &modul1::szia; és persze a kimenet: Betöltődött a modul1 modul. Rettenetesen örülök neked! Kitörlődött a modul1 modul. Ezek után két alapvető kérdés merül fel: Mi van a modulban? Minek a push @INC ... utasítás? Az elsőre nagyon könnyű válaszolni: package modul1; BEGIN { print "Betöltődött a modul1 modul.\n"; } END { print "Kitörlődött a modul1 modul.\n"; } sub szia { print "Rettenetesen örülök neked!\n"; } 1; és ez a válasz máris további kérdéseket generált: mi az a BEGIN és mi az az END. Csak sorjában. Az a push utasítás az INC tömb végére rakja az egy pontot tartalmazó füzért. Ezt már az eddigiek alapján is tudnod kell. Az INC tömb egy speciális tömb, amelyet a Perl interpreter használ, és a modul fájlokat azokban a könyvtárakban (directory-kban) próbálja megkeresni, amelyek szerepelnek ebben a tömbben. Írassuk ki az én rendszeremen: C:\Perl5\lib\i386-win32 C:\Perl5\lib . Ebből például látszik az, hogy ezt a könyvet Windows rendszeren írom.
Objektum orientált programozás
A Perl programozási nyelv – röviden
79/26
Ez a fejezet egy kicsit kilóg a sorból, ezt ugyanis nem én írtam, hanem Mörk Péter ([email protected]). Ez a fejezet hiányzott, Péter pedig írt nekem egy levelet, hogy ő ezt egyszer már megírta. És szerintem jó. Akkor meg minek kétszer feltalálni a melegvizet... Sziasztok! Ez a levél úgy született, hogy valamelyik vasárnap délután Dublin belvárosában sétálva egyszer csak megvilágosodott előttem az objektum -orientált programozás lényege. Ez pedig nem más, mint két angol szóba tömörítve: "code reuse". A most következő bevezetőben tehát lerántom a fátylat az objektum- orientált programozásról :-), utána bemutatok egy saját gyártmányű működöképes (ténlyeg!) objektum-orientált példaprogramot Perlben megírva, részletesen kitérve a Perl szokás szerint "patologically eclectic" megoldásaira. Az objektum-orientált programozás klasszikus példája a következő: Vegyünk egy általános síkidomosztályt, aminek van egy draw() függvénye. Származtassunk ebből egy "téglalap", egy "háromszög" és egy "kör" osztályt; a leszármazott osztályokban mindegyikben lesz egy-egy draw() függvény, tehát ugyanazt a függvényt fogjuk használni a téglalap, a kör, illetve a háromszög ábrázolásához. Hurrá! A példa azért tipikus "marketing bullshit", mert azt sugallja, hogy a draw() függvényt elég egyszer megírnunk, a téglalap, a háromszög és a kör ezt örökli, vagyis kódírást takarítottunk meg. Sajnos nem ez a helyzet. Objektum-orientáltan is ugyanannyi kódot kell írnunk, mint anélkül, mint ahogyan struktúráltan programozva is ugyanannyi munkánk van, mintha mezítlábas tömbökkel dolgoznánk. Az előny nem abból ered, hogy valamit meg tudunk spórolni, hanem abból, hogy objektum-orientáltan programozva a kód struktúráltabb, magyarán ÁTTEKINTHETŐBB lesz. Nagyon jó példa erre a Windows rendszerhívások gyűjteménye (Application Programming Interface, röviden API; ahogy a Microsoft terminológia nevezi.) Ezt még akkor kezdték el fejleszteni, amikor Bill Gates azt nyilatkozta a Borland Turbo Pascalról, hogy "Ha az objektum-orientált programozás tényleg olyan nagy durranás, akkor mégis miért van az, hogy az alkalmazásokat jórészt sima C-ben írják?" Már a Windows 3.1 API is nyolcszáz körüli függvényből állt, amit ajánlatos volt fejben tartania a programozónak, hacsak nem akarta programozás közben folyton a könyvet bújni, a Win32 API pedig teli van csupa hasonló nevű, hasonló funkciójú, de kissé eltérő paraméterezésű függvényekkel (CreateDialog, CreateEvent, CreateMailslot, stb. Közel hetven olyan függvény van, aminek a nevében szerepel a "Create" szó...) Pedig mennyivel egyszerűbb lenne a dolog, ha valamilyen szisztéma szerint csoportosítanánk a függvényeket. Nos, az objektum-orientált programozás éppen ezt teszi. (A Microsoft Visual C++ osztályokat definiál a Win32 API függvények csoportosítására. Osztályokból is nagyon sok van, ez tehát önmagában még nem teszi triviálissá a programozást, de némileg egyszerűsíti a dolgot.) A kettes számú használható ötlet az, hogy az így képezett függvény-csoportokat hozzárendeljük egy adatstruktúrához. Ha előrelátóak vagyunk, akkor épp ahhoz, amelyiken műveleteket végeznek :-) Ezt az adatstruktúrát, a hozzá rendelt függvényekkel együtt objektumnak hívjuk, innen a módszer elnevezése. Az objektumok adatokat tárolnak, amelyeket az objektum függvényeivel lehet manipulálni. Ha igazán civilizáltan akarunk programozni, akkor az objektum adatait csak függvényein keresztül olvasssuk és módosítjuk. Ezzel megvalósul az "adat-enkapszuláció" (Császár Péter szép szava), azaz az objektum belső szerkezete rejtve marad a programozó elől, így egyrészt nem szükséges megtanulnia, hogy az hogyan működik belülről, másrészt elkerülhető, hogy az objektum belsejébe nyúlva véletlenül elbarmoljon valamit. Az objektumokat az osztályokból hozzuk létre, tehát az osztályok a "minták", amik alapján az objektumok készülnek. A harmadik ötlet az, hogy az oszályok egymásból származtathatók: ilyenkor a leszármazott osztály örökli a szülő függvényeit. Csakhogy: ez még önmagában nem jelenti azt, hogy a származtatott osztályban (és az ebből létrehozott objektumokban) minden további nélkül használhatjuk az öröklött függvényeket. A klasszikus példában például nem ez a helyzet, mivel egy kört nyilvánvalóan másképp kell megjeleníteni, mint egy téglalapot. A draw() függvényt tehát újra meg kell írnunk, a származtatott osztály
A Perl programozási nyelv – röviden
79/27
igényeinek megfelelően. Mi ebben a buli? Egyrészt az, hogy nem biztos, hogy minden függvényt újra kell írnunk. A másik, hogy miután megírtuk a szükséges új függvényeket, a háromszöget ábrázoló függvényt ugyanúgy draw()-nak hívják majd, mint a kört vagy a téglalapot ábrázoló függvényt, ha tehát valaki más akarja használni az objektumainkat, aki nem ismeri pontosan a függvények belső felépítését (ez a valaki mi magunk is lehetünk, pár évvel később), az nem három különféle rajzolófüggvényt lát, hanem csak egyet (és mellé három különféle osztályt). Code reuse rulez. Az öröklésnek van egy fájdalmas velejárója is: ha saját magunk hozunk létre osztályokat a korábban már meglévőkből, az objektumok megszűnnek fekete doboznak lenni. Amint módosítani akarunk valamit egy osztályon, rögtön szükségünk van az osztályok belső felépítésének pontos ismeretére, másképp nem tudnánk megírni a szükséges új függvényeket. A "fekete doboz"-ként kezelhetőség tehát csak az OBJEKTUMOK használóira vonatkozik, az osztályok újrafelhasználóira nem! Ez az örökösödési adó, amit a szülőosztály függvényeinek örökléséért kell fizetnünk. Perlben is lehet objektum orientáltan programozni, mindjárt el is mesélem, hogy hogyan: ELSŐ RÉSZ: a hozzávalók Mint tudjátok, a Perl-ben minden változó globális, kivéve amit lokálisnak definiálunk. Ez nem mindig kényelmes, ezért bevezették a package fogalmát: a package kulcsszóval el lehet a program részeit elválasztani egymástól. Ha ezt írjuk: package Egyik; $global = "egyik"; . . . package Masik; $global = "masik"; . . . . Akkor az Egyik package-ban lévő $global változó globális lesz az Egyik package függvényeire nézve, miközben a Masik package függvényei erről mit sem tudnak. Nekik a $global értéke "masik". Célszerűen úgy szokták szervezni a dolgot, hogy a package-k külön fájlokba kerülnek, és az use operátor segítségével emelik be őket a program elején. Beemelni bármilyen perl programot lehet egy másikba, ez azzal egyenértékű, mintha a két programot futtatás előtt egyetlen fájlba másoltuk volna össze. A gyakran használt függvényeket ki szokták tenni egy külön fájlba és utána beemelik a scriptbe, ha használni szeretnék a függvénykönyvtár valamelyik függvényét. A nagyon gyakran használt függvénykönyvtárakat a perl\lib könyvtárba teszik és a ".pm" kiterjesztést adják neki (pm annyit tesz: Perl Module). A Perl modult tartalmazó fájl neve ugyanaz, mint a modul neve. Van még egy kis kavarás az "use" és a "require" közötti árnyalatnyi különbséggel, de ennek most a történetünk szempontjából nincs szerepe, ezért inkább hallgatok róla. Ahhoz, hogy objektum orientált programot írjunk, lényegében három dologra van szükség: objektumokra, osztályokra és metódusokra. objektumok
A Perl programozási nyelv – röviden
79/28
Az objektumokat a Perlben referenciák (mutatók) testesítik meg. Természetesen kell valami megoldás arra, hogy az objektumra mutató referenciákat megkülönböztessük a közönséges referenciáktól. Ezt úgy tesszük meg, hogy az objektumok referenciáit "megszenteljük" a bless utasítás segítségével. A blessed referencia mindössze annyiban különbözik a közönséges referenciától, hogy a Perl tudja róla, hogy ez egy objektumot jelent és azt is, hogy ez az objektum melyik osztályba tartozik. A $mokus referenciát a következő módon tehetjük a Erdolakok osztály objektumává: bless $mokus, "Erdolakok"; A közönséges referenciával csak a változóra hivatkozhatunk, amelyikre a referencia hivatkozik: ${$ref} = "bikmakk"; Az objektum-referenciával egyrészt hivatkozhatunk az objektum adataira: ${$objref} = "object-bikmakk"; másrészt meghívhatjuk az objektum függvényeit: $objref->ThisIsAMethod(); Ezeket a függvényeket mostantól metódusoknak hívjuk. Természetesen egy objektum-referencia csak egyetlen változóra mutathat. A gyakorlatban nem sokra mennénk egy olyan objektummal, aminek egyetlen adata egy mezítlábas skalár; szerencsére a Perlben vannak hash listák is, és persze az objektum-referencia mutathat hash-listára is, arról pedig már tudjuk, hogy gyakorlatilag bármiből bármennyit tartalmazhat. A gyakorlatban tehát úgy hozunk létre objektumot, hogy a bless utasítással objektum-referenciaként deklarálunk egy üres hash-listára mutató referenciát. A hash listán aztán az objektum valamennyi saját adata tárolható. osztályok Az osztály nem más, mint egy package, a package-ban definiált függvények pedig az osztály metódusai. Amikor a bless-el létrehozunk egy objektumot, megadhatjuk, hogy az objektum melyik osztályba tartozzon. (Ha nem adunk meg típust, akkor a létrejött objektum abba az osztályba fog tartozni, amelyik package-ban a bless utasítást kiadtuk.) metódusok Az osztály-package függvényei az osztály metódusai. Amikor létrehozunk az osztályba tartozó objektumot, az új objektum megkapja az osztály metódusait. Ezeket mostantól objektum-metódusoknak hívjuk. Az osztály metódusait az osztálynéven keresztül hívjuk meg: $mokus = Erdolakok->create(); Az objektum metódusait pedig az objektumra mutató referencián keresztül: $mokus->EatNuts("chesnut"); $mokus->EatNuts("walnut"); Van egy lényeges különbség az osztály-medódusok és az objektum-metódusok között. Amikor egy osztálymetódust hívunk meg, a Perl az átadott argumentumlista elé automatikusan odailleszti az osztály típusát. A leggyakrabban meghívott osztály-metódus a konstruktor függvény: ezt osztály- metódusként hívjuk meg, és egy objektum-referenciát ad vissza. (A konstruktor függvény neve bármi lehet, csak az a lényeg, hogy egy objektum-referenciát hozzon létre.)
A Perl programozási nyelv – röviden
79/29
Ezzel szemben az objektum-metódus meghívásakor nem az osztály típusa, hanem az objektum mutatója kerül a paraméterlista elejére. Erre az objektum-metódusnak mindenképp szüksége van, másképp nem tudna hozzáférni az objektum saját adataihoz. Az osztály-medótusok és objektum-metódusok deklarációja között nincs formai különbség. Sőt, mind a két féle képpen meghívhatjuk őket. Ha egy metódus objektumon végez műveletet, akkor természetesen nem hívhatjuk meg osztály- metódusként, mert hibaüzenetet kapunk. A metódusok megírásakor ezt figyelembe kell vennünk. A gyakorlatban ez nem olyan nagy probléma: minden függvényt objektum-metódusként használunk, kivéve a konstruktort, amit osztály- metódusként hívunk meg. Ha nagyon bolondbiztos kódot akarunk írni, a paraméterlista első eleméből eldönthetjük, hogy a függvényt osztály- metódusként, vagy objektum-metódusként hívták-e meg. Van értelme annak, hogy egy metódust egyszer így, másszor meg úgy hívjuk meg: ezért nincsenek kitiltva a nyelvből. (Hogy mi az értelme, arról talán majd legközelebb.) Nézzünk egy egyszerű osztály-metódust: package Erdolakok; sub create { my $type = shift; my $self = {}; return bless $self, $type; } Ha osztály-metódusként meghívjuk ezt a függvényt, akkor a következő történik: a Perl ugyebár a paraméterlista elé beszúrja az osztály nevét. Ezt mindjárt ki is vesszük a $type változóba a shift-tel. A második sorban létrehozunk egy hash listára mutató üres referenciát, a harmadik sorban ebből objektumot csinálunk és visszaadjuk a hívónak. Ha azt mondjuk, hogy: $mokus = Erdolakok->create(); akkor létrehozunk egy, az Erdolakok osztályba tartozó objektumot. Ahhoz, hogy a mókus diót és mogyorót is tudjon enni, megfelelő metódusra is szüksége van. Például valami ilyesmire: sub EatNuts() { my $self = shift; my $food = shift; if($food eq "chesnut") { # ide jön a dióevés implementációja } elsif($food eq "walnut") { # ide jön a mogyoróevés implementációja } else { print "I can't eat this $food\n"; } }
A Perl programozási nyelv – röviden
79/30
Ha objektum-metódusként hívjuk meg ezt a függvényt, akkor a Perl az objektum referenciát teszi a paraméterlista elejére, amit mindjárt át is veszünk egy lokális változóba a függvény elején. Ez a lokális változó használható azután az objektum belső adatainak eléréséhez. Valahogy így: if($food eq "chesnut") { $self{'FOOD_CONSUMED'} = $self->EatChesNut(); $self{'HUNGRY'} = "no"; $self{'WATER_CONSUMED'} = $self->DrinkWater(); $self{'THIRSTY'} = "no"; $self{'HAPPY'} = "yes"; } rövid összefoglalás A Perl-ben az osztályok package-k, amelyek függvényeket tartalmaznak. Ezeket a függvényeket a Perl (és a Pascal is) metódusoknak nevezi. Az osztály metódusait az osztály nevén keresztül hívhatjuk meg, bár ez - az objektumokat létrehozó osztály-metódus kivételével - ritkán szokás. Az objektum nem más, mint egy változóra (általában hash listára) mutató referencia, amit a bless operátorral hozzárendelünk egy objektum osztályhoz. Amikor létrehozunk egy objektumot, az automatikusan megkapja az osztály metódusait. Ezáltal az osztályban definiált metódusok az objektum objektum- metódusaivá válnak. Az objektum-mutatón keresztül meghívhatjuk az objektum metódusait, illetve hozzáférhetünk közvetlenül az objektum adataihoz. A Perl nem rejti el az objektum változóit a programok elől, viszont elvárja a programozótól, hogy ne turkáljon az objektumok saját adataiban. ("A Perl module would prefer that you stayed out of its living room because you were not invited, not because it has a shotgun. /Larry Wall /") Ennyi bevezetés után következzék egy (működőképes!) példa: MÁSODIK RÉSZ: hab a tortán A történet a következő: Van egy telefonszámokat tároló szövegfájlunk, ami kb. így néz ki: Peter Peter Peter David Miki Arpad Miki Zoli Ali
6797 2897618 +3646381385 1234 3456 4567 3456 3332 4562
Fontos: A nevet tabulátor karakter (\t) választja el a telefonszámtól. Egy olyan objektumot szeretnénk készíteni, ami elrejti előlünk a szövegfájlt és metódusokat ad a telefonkönyv kezelésére. Első lépésként csak annyit akarunk elérni, hogy létre tudjunk hozni egy ilyen objektumot (ez eléggé lényeges) és hogy név szerint tudjunk keresni az objektum által reprezentált adatbázisban. A telefonkönyv-objekum létrehozásakor megnyitjuk a fájlt és a tartalmát beolvasssuk egy hash-listába. A keresést ezen a listán végezzük, hogy ne kelljen újra beolvasni a szövegfájlt minden egyes alkalommal, amikor meg karunk keresni egy számot.
A Perl programozási nyelv – röviden
79/31
A név-telefonszám párokat hash listán tároljuk, a nevet használva kulcsként. Egy kis komplikáció: a hashlisták kulcsai egyediek. Ez azt jelenti, hogy ha egy emberhez több telefonszám is tartozik, azt csak úgy tudjuk tárolni, hogy nem skalárokat, hanem tömböket tárolunk a hash listán. Valahogy így (az egymás alatti pontok a telefonszámokat tartalmazó tömbök elemeit jelképezik): Peter - David - Miki - Arpad - Zoli - Ali . . . . . . . . . . . . . . . . . . Az osztályt Perl modulként írtam meg: ez azt jelenti, hogy a perl/lib könyvtárba kell tenni, és a fájl nevének meg kell egyeznie a modul nevével. A package-okat nem kötelező modulként megírni, az egész példaprogramot rakhattam volna egyetlen fájlba is. Azért válaszottam mégis szét, hogy jobban elkülönítsem a metódusokat definiáló objektumosztályt az objektumot használó kódtól. Kell először is egy konstruktor metódus: sub New { my $type = shift; my $self = {}; bless $self, $type; my $status = $self->Init( @_ ); print $status, return "" if $status; return $self; } Figyeljük meg, hogy a bless művelet (az objektum létrehozása) után máris használhatjuk az objektum metódusait: itt például az Init() metódust hívjuk meg. A visszatérési érték a hibaüzenetet tartalmazza. Ha valami gixer volt, akkor kinyomtatjuk a hibaüzenetet és üres stringet adunk vissza a hívónak, aki innen tudja meg, hogy az objektumot nem sikerült létrehozni. Ha a hibaüzenet üres string, akkor az objektumreferenciát visszaadjuk a hívónak és ezzel az objektum megkezdi szoftver-életét. Adós maradtam az Init() függvénnyel, pedig a konstruktornak szüksége van rá. Az Init() ugyan objektum-metódus, de csak a konstruktor osztály-metódus használja. sub Init() { my ($self, $file) = @_; open(BOOK, $file) or return "Init() failed: can not open $file\n"; while( ) { chop; my ($name, $number) = split /\t/; $self->AddEntry($name, $number); } close BOOK;
A Perl programozási nyelv – röviden
79/32
return ""; } Erről megint nem tudok többet mondani, mint amit már elmondtam a korábbi leckékben. Az egész osztály legérdekesebb függvénye az AddEntry(): sub AddEntry() { my ($self, $name, $number) = @_; if($self{$name}) { push @{$self{$name}}, $number; } else { $self{$name} = [ $number ]; } } Vadul néz ki, pedig nagyon egyszerű dolgot csinálunk. Először is megnézzük, hogy a megadott név szerepel-e már a listán: if($self{$name}) ha nem, akkor hozzáadunk a listához egy újabb elemet. Ennek az elemnek a kulcsa a $name változóban tárolt string, értéke pedig egy tömb (erre utalnak a [] jelek), aminek egyelőre egyetlen eleme a $number változóban tárolt telefonszám. $self{$name} = [ $number ]; Egy árnyalattal bonyolultabb a helyzet, ha a név már létezik: ilyenkor a már létező tömbhöz kell adunk egy újabb elemet. Szerencsére a push utasítást pont erre találták ki: push @{$self{$name}}, $number; (Kicsit sok benne a kukac meg a dollár, de ha nézitek egy ideig akkor rájöttök, hogy mindenből pont annyi van, amennyi kell. Ha nem hiszitek, akkor futtasátok le a programot - működik :-) Ezek után már csak a kereső metódusra van szükség. Íme: sub LookupByName { my ($self, $name) = @_; return $self{$name}; } (Ennél egyszerűbb metódust nagyon nehéz nenne írni :-) HARMADIK RÉSZ: csokoládé díszítés lássuk most ezek után a főprogramot, ami az előbb definiált osztályból létrehozott objektumot használja! Mindjárt az elején meg kell mondanunk, hogy melyik osztályt szeretnénk használni: use Phone;
A Perl programozási nyelv – röviden
79/33
Ha ez megvan, akkor meghívjuk az _osztály_ kreátor függvényét, hogy létrehozzuk vele a $konyv nevű objektumot. A telefonszámokat tartalmazó fájl elérési útját paraméterként adjuk meg. A program során később is bármikor meghívhatjuk az osztály bármelyik függvényét, ebben a példában viszont csak a már létező objektum metódusaival operálunk. Ennyi szöveg után egy kis szintaktika: a Phone osztály New metódusát a következő módon hívjuk meg: $konyv = Phone->New("e:/home/stsmork/script/book.txt"); Ha a $konyv változóban tárolt visszatérési érték nulla, akkor az objektumot nem sikerült létrehozni. Minden más esetben egy hash listára mutató referenciát kapunk. Ez a "blessed" hash lista tárolja az objektum adatait. A hash referencia "megszentelt", ezért a Perl tudja róla, hogy egy objektum- osztályhoz tartozik és azt is, hogy melyikhez. A $konyv objektum metódusait szintén a -> operátor segítségével hívhatjuk meg. Bill Gates telefonszámát például így kérdezhetjük le: $Aref = $konyv->LookupByName( "Bill Gates" ); A visszatérési érték a telefonszámok tömbjére mutató referencia. Ennek a referenciának a segítségével már gyerekjáték kinyomtatni a megtalált telefonszámokat: foreach $number ( @{$Aref} ) { print "$number\n"; } A teljes program a fenti műveleteken kívül még három másik dolgot csinál: ellenőrzi, hogy az objektumot sikerült-e létrehozni, ellenőrzi, hogy a LookupByName metódus adott-e vissza értéket, valamint a keresés előtt beolvassa a konzolról a keresendő nevet a $name változóba: print "\nName: "; $name = ; chop($name); Emlékeztetőül: a mindig egy teljes sort olvas be a fájlból. (Másképp fogalmazva: addig olvas, amíg \n-t nem talál) A chop()levágja az argumentumként megadott string utolsó karakterét. (Itt arra használjunk, hogy megszabaduljunk a $name változó végéhez ragadt \n-től, ami akkor került oda, amikor a begépeléskor leütöttük az ENTER-t.) A teljes példaprogram phone.pm ... telefon.pl ... book.txt ebben a három fájlban található meg. Külön köszönet Császár Péternek, az objektum-orientált programozás elméleti kérdéseivel kapcsolatos konzultációért.
Beépített függvények A függvények, amelyek ebben a fejezetben le vannak írva kifejezésekben használhatók. Két fő kategóriába lehet őket sorolni: vannak lista operátorok és unáris operátorok. A lényegi különbség ezek
A Perl programozási nyelv – röviden
79/34
között abban van, hogy míg egy unáris operátor pontosan egy argumentumot dolgoz fel, és így az argumentuma véget ér legkésőbb a következő vesszőnél, addig a lista operátorok esetében a vessző csupán az argumentumokat választja el. Az unáris operátorok általában skalár környezetet nyújtanak az argumentumuknak, míg a lista operátorok skalár vagy lista környezetet nyújtanak. Ha mind a kettőt nyújtanak, akkor a skalár argumentumok mindig megelőzik a lista argumentumot, mivel mindig csak egy lista argumentum lehet. Például a splice függvény három skalár és egy lista argumentummal dolgozik. A következő szintaxis leírásban azok a helyek, ahol a lista operátorok lista környezetet nyújtanak az argumentumaik számára LIST kulcsszóval esznek jelölve. Az ilyen listák tartalmazhatnak skalár argumentumokat vesszőkkel elválasztva, és listákat, amelyeket a Perl egyszerűen befűz a listába minden egyes elemükkel, egyre hosszabb listát előállítva. A LIST minden eleme vesszővel van elválasztva. Bármelyik függvény, amelyet itt felsorolunk használható az argumentumait bezáró zárójellel, vagy anélkül. (A szintakszis leírásban nem használunk zárójeleket.) Ha használunk zárójeleket, akkor a nagyon egyszerű szabály szerint: ha függvénynek látszik, akkor függvény és a precedencia nem számít. Egyéb esetekben unáris, vagy lista operátor és az operátor precedenciák számítanak. A közök (szóköz, tab, újsor) a függvény neve és a paraméterek körüli nyitózárójel között nem számít, ezért néha igencsak érdemes óvatosnak lenni: print 1+2+3; print(1+2) + 3; print (1+2)+3; print +(1+2)+3; print ((1+2)+3);
# eredmény 6. # eredmény 3. # szintén 3! # eredmény 6. # eredmény 6.
és a kimenet: 63366 Ha a Perl értelmezőt a -w opcióval futtatod, akkor ezekre a dolgokra figyelmeztet. Azon függvények esetében, amelyek skalár és lista környezetben is használhatóak ha olyan hiba történik, amelyik miatt a program futásának nem kell megszakadnia nem definiált érték undef illetve nulla hosszúságú lista a visszatérési érték. A következő szabály örökérvényű: NINCS ÁLTALÁNOS SZABÁLY A LISTÁK SKALÁRRA VALÓ KONVERZIÓJÁRA! Minden egyes operátor és függvény, amelyik listát szeretne visszaadni, de skalár környezetben lett meghívva maga dönt arról, hogy melyik konverziós lehetőség a legmegfelelőbb. Néhány operátor annak a listának a hosszát adja vissza, amelyiket lista környezetben adott volna vissza. Más operátorok a lista első elemét adják eredményül. Megint más operátorok a lista utolsó elemét adják vissza. Ismét mások a sikeresen végrehajtott műveletek számát adják. Általánosságban azt az értéket adják vissza, amelyikre általában a leginkább szükséged van, kivéve ha egyformaságra van szükséged. Perl függvények kategória szerint Itt vannak a Perl függvények kategória szerint, és néhány olyan dolog is, amelyik nem függvény, de annak látszik, mint néhány Perl kulcsszó és operátor. Néhány függvény több helyen is előfordul. Függvények skalárok és füzérek kezelésére chomp, chop, chr, crypt, hex, index, lc, lcfirst, length, oct, ord, pack, q/STRING/, qq/STRING/, reverse, rindex, sprintf, substr, tr///, uc, ucfirst, y/// Reguláris kifejezések és mintaillesztés
A Perl programozási nyelv – röviden
79/35
m//, pos, quotemeta, s///, split, study Numerikus függvények abs, atan2, cos, exp, hex, int, log, oct, rand, sin, sqrt, srand Függvények igazi @TÖMB-ökhöz pop, push, shift, splice, unshift Függvények listákhoz grep, join, map, qw/STRING/, reverse, sort, unpack Függvények igazi %HASH-ekhez delete, each, exists, keys, values Input és output függvények binmode, close, closedir, dbmclose, dbmopen, die, eof, fileno, flock, format, getc, print, printf, read, readdir, rewinddir, seek, seekdir, select, syscall, sysread, syswrite, tell, telldir, truncate, warn, write Függvények fix hosszúságú adat rekordokhoz pack, read, syscall, sysread, syswrite, unpack, vec Függvények fájl kezelőkhöz (handle) és könyvtárakhoz -X , chdir, chmod, chown, chroot, fcntl, glob, ioctl, link, lstat, mkdir, open, opendir, readlink, rename, rmdir, stat, symlink, umask, unlink, utime Kulcsszavak, és programvezérlés caller, continue, die, do, dump, eval, exit, goto, last, next, redo, return, sub, wantarray Kulcsszavak caller, import, local, my, package, use Vegyes függvények defined, dump, eval, formline, local, my, reset, scalar, undef, wantarray Processzekhez és processz csoportokhoz alarm, exec, fork, getpgrp, getppid, getpriority, kill, pipe, qx/STRING/, setpgrp, setpriority, sleep, system, times, wait, waitpid Perl modul kulcsszavak do, import, no, package, require, use Osztályok és objektum orientált kulcsszavak bless, dbmclose, dbmopen, package, ref, tie, tied, untie, use Alacsonyszintű socket függvények accept, bind, connect, getpeername, getsockname, getsockopt, listen, recv, send, setsockopt, shutdown, socket, socketpair System V processzek közötti kommunikációs függvények msgctl, msgget, msgrcv, msgsnd, semctl, semget, semop, shmctl, shmget, shmread, shmwrite
Felhasználói és csoport információs függvények endgrent, endhostent, endnetent, endpwent, getgrent, getgrgid, getgrnam, getlogin, getpwent, getpwnam, getpwuid, setgrent, setpwent
A Perl programozási nyelv – röviden
79/36
Hálózati információs függvények endprotoent, endservent, gethostbyaddr, gethostbyname, gethostent, getnetbyaddr, getnetbyname, getnetent, getprotobyname, getprotobynumber, getprotoent, getservbyname, getservbyport, getservent, sethostent, setnetent, setprotoent, setservent Időhöz kapcsolódó függvények gmtime, localtime, time, times A Perl5-ben új függvények abs, bless, chomp, chr, exists, formline, glob, import, lc, lcfirst, map, my, no, prototype, qx, qw, readline, readpipe, ref, sub*, sysopen, tie, tied, uc, ucfirst, untie, use * - sub a Perl4 változatában kulcsszó volt, de a Perl5-ben operátor, amely kifejezésekben használható. Perl5-ben aktualitásukat vesztett függvények dbmclose, dbmopen A Perl függvények ABC sorrendben -X FILEHANDLE -X EXPRESSION -X Általában fájl teszt, amelyben az X valamelyik betű az alábbi felsorolásból. Ez az unáris operátor egy argumentumot fogad (ezért unáris) amelyik egy fájlkezelő vagy a fájl neve, és megnézi, hogy a betűhöz rendelt állítás igaz-e. Ha az argumentum hiányzik, akkor automatikusan a $_ változót veszi figyelembe a program kivéve a -t esetet, amelyik ilyen esetben a szabványos bemenetre STDIN vonatkozik. Amennyiben más nincs definiálva az operátor az 1 értéket adja vissza igaz esetben, a '' értéket hamis esetben és undef értéket ha a fájl nem létezik. A furcsa név ellenére ugyanazok a precedencia szabályok vonatkoznak erre az oprátorra, mint bármely más unáris operátorra, és az argumentumok ugyann úgy zárójelezhetőek. Az operátorok listája: -r a fájl olvasható az aktuális felhasználó által. (effective uid,gid) -w a fájl írható az aktuális felhasználó által. (effective uid,gid) -x a fájl végrehajtható az aktuális felhasználó által. (effective uid,gid) -o a fájl az aktuális felhasználó tulajdona. (effective uid,gid) -R a fájl olvasható a valódi felhasználó által. (real uid,gid). -W a fájl írható az aktuális felhasználó által. (real uid,gid). -X a fájl végrehajtható az aktuális felhasználó által (real uid,gid). -O a fájl az aktuális felhasználó tulajdona. (real uid,gid) -e a fájl létezik -z a fájl nulla hosszú -s a fájl nem nulla hosszú. Visszatérési érték a bájtok száma. -f a fájl egyszerű fájl. -d a fájl könyvtár -l a fájl szimbólikus link. -p a fájl egy megnevezett csatorna -S a fájl egy socket. -b a fájl block special fájl. -c a fájl karakter speciális fájl. -t a fájlkezelő egy tty-hoz (terminál) nyitott -u a fájl setuid bitje be val állítva -g a fájl setgid bitje be van állítva -k a fájl sticky bitje be van állítva -T a fájl szöveges fájl. -B a fájl bináris (-T ellentéte). -M a fájl kora napokban a Perl script indulásakor. -A ugyanez, de a legutolsó hozzáférési időt figyelembe véve
A Perl programozási nyelv – röviden
79/37
-C ugyanez de inode változási időre A fájlhozzáférési operátorok, mint a -r, -R, -w, -W, -x és -X kizárólag csak a hozzáférési engedélyeket vizsgálják, ezen kívül még igen sok oka lehet annak, ha a program nem tudja például írni az egyik fájlt (például betelt a diszk). Ugyanakkor a superuser számára a -r, -R, -w és -W mindig 1-et ad vissza értékként, -x és -X 1-et ad vissza értékként ha bármelyik végrehajtási bit be van billentve. Így azok a programok, amelyeket a superuser futtat a stat függvényt kell, hogy használják, hogy a fájlok valódi módját megkapják, vagy a felhasználói azonosítót (uid) kell erre az időre átállítani. Példa: while (<>) { chop; next unless -f $_; ... }
# ignore specials
Megjegyzendő, hogy -s/a/b/ nem egy string csere mínusz egyszerese, hanem fájl méretre való hivatkozás, osztva a-val és b-vel. Ugyanakkor -exp $foo úgy működik, ahogy várjuk, mert csak az egybetűs operátorokat kezeli a Perl fájl tesztként. A -T és -B kapcsolók a következőképpen működnek. A fájl első blokkját vizsgálja meg a rendszer, és keres bűvös kontrol kódokat, illetve olyan karaktereket, amelyeknek a legfelső bitje 1. Ha több mint 30% ilyen karaktert talál, akkor a fájl -B különben -T. Bármilyen fájl, amelyik nulla értékű karaktert tartalmaz az első blokkban bináris fájl. Ha ezen kapcsolókat fájlkezelőkre alkalmazzuk, akkor a beolvasott puffert vizsgálja meg a rendszer az első blokk helyett. Mind a két kapcsoló igaz értéket ad vissza nulla fájlon, illetve ha olyan fájlkezelővel hívják meg, amely EOF-on áll. Mivel a -T és -B opciókhoz a fájl olvasása szükséges, azért érdemes a fájlt először a -f operátorral megvizsgálni, mint a next unless -f $file && -T $file. Ha bármelyik fájl vizsgálat, beleértve a stat és lstat operátorokat is fájlkezelő, vagy fájlnév helyett magában álló aláhúzás karaktert kap argumentumként, akkor az utolsó megvizsgált fájlra adja az eredményt. Ezzel egy rendszerhívást megspórol a rendszer. (Kivéve a -t kapcsolót, és az is megjegyzendő, hogy a lstat és -l a szimólikus link és nem a valódi fájl adatait hagyja a stat struktúrában. Például: print "Can do.\n" if -r $a || -w _ || -x _; stat($filename); print "Readable\n" if -r _; print "Writable\n" if -w _; print "Executable\n" if -x _; print "Setuid\n" if -u _; print "Setgid\n" if -g _; print "Sticky\n" if -k _; print "Text\n" if -T _; print "Binary\n" if -B _;
abs VALUE Az argumentum abszolút értékét adja vissza. accept NEWSOCKET,GENERICSOCKET
A Perl programozási nyelv – röviden
79/38
Elfogad egy bejövő socket kapcsolatot, ahogy az accept(2) rendszerhívás teszi. A packet címet adja vissza siker esetén, FALSE értéket egyébként. alarm SECONDS Gondoskodik róla, hogy a paraméterként megadott számú másodperc múlva egy alarmot kapjon a processz. (Néhány gépen egy másodperccel hamarabb.) Egyszerre csak egy számláló működhet. Minden egyes hívás a korábbi hívások hatását törli, és ha 0 argumentummal hívjuk meg a függvényt, akkor minden egyes korábbi hívás hatását törli újabb alarm előjegyzése nélkül. A visszatérési érték az előző alarmig tartó idő. Ennél nagyobb pontosságú időállításhoz a Perl syscall felületét lehet használni a setitimer(2) rendszerfüggvényhez, ha a rendszer ezt támogatja, vagy a select függvényt. Nem ajánlott az alarm és sleep hívások keverése. atan2 Y,X Y/X arcus tangense -PI és PI között. bind SOCKET,NAME Hozzáköt egy hálózati címet egy sockethez, mint ahogy azt a bind rendszerhívás teszi. TRUE értéket ad vissza siker esetén és FALSE értéket hiba esetén. A NAME egy a socketnek megfelelő packet cím kell, hogy legyen. binmode FILEHANDLE A fájlt íráshoz és olvasáshoz bináris módba állítja minden olyan operációs rendszeren amelyik különbséget tesz bináris és szöveges fájlok között. A szöveges fájloknál a bemeneten a CR LF karakterek LF karakterekké konvertálódnak, és a kimeneten fordítva. binmode nincs hatással semmire UNIX alatt, de DOS, Windows, Windows95, WindowsNT és más modern operációs rendszereken kötelező használni, ellenkező esetben igen érdekes eredményeket adhat a rendszer. Gyakorlatilag a UNIX kivételével minden rendszeren szükséges ennek a függvénynek a megfelelő használata. Ha FILEHANDLE egy kifejezés, akkor ennek az értékét használja a rendszer, mint a fájlkezelő nevét. bless REF,CLASSNAME bless REF Ez a függvény megmondja a hivatkozott objektumnak (REF), hogy a CLASSNAME csomaghoz tartozik, illetve az aktuális csomaghoz, ha CLASSNAME nincs megadva. A kényelem kedvéért a visszatérési érték az objektumhoz valóü referencia, mivel a bless meghívása gyakran egy objektum összeállítás utolsó lépése. Mindig a kétargumentumos változatot használd, ha olyan konstruktor eljárást írsz, amelyik örökölhető. caller EXPRESSION caller Az aktuális szubrutinhívás környezetét adja vissza. Skalár környezetben TRUE értéket ad vissza, ha van hívó, azaz ha szubrutinban vagyunk, vagy eval vagy require környezetben, FALSE értéket egyébként. Lista környezetben a visszatérési érték ($package, $filename, $line) = caller; Ha EXPRESSION is meg van adva, akkor néhány olyan extra információt is visszaad, amelyet a debugger használ. EXPRESSION értéke mondja meg, hogy hány hívási keretet menjen vissza az aktuálishoz viszonyítva. ($package, $filename, $line,
A Perl programozási nyelv – röviden
79/39
$subroutine, $hasargs, $wantargs) = caller($i); Amikor a DB csomagon belül kerül meghívásra még további részletes információ is kiértékelődik, nevezetesen a @DB::args listába bekerül a szubrutin argumentumainak a listája. chdir EXPRESSION Megváltoztatja a munkakönyvtárat EXPRESSION-re, ha lehetséges. Ha EXPRESSION hiányzik, akkor a home könyvtárba megy. A visszatérési értéke TRUE siker esetén, egyébként FALSE. Egy példa olvasható a die függvény magyarázatánál. chmod LIST A hozzáférési engedélyeket változtatja meg fájlok listájára. A lista első eleme numerikus kód kell, hogy legyen, amely általában oktális. A visszatérési érték azon fájloknak a száma, ahol sikeres volt az érték beállítás. $cnt = chmod 0755, 'foo', 'bar'; chmod 0755, @executables; chomp VARIABLE chomp LIST chomp Ez valamelyest biztonságosabb változata a chop függvénynek. Leveszi a sorvégződést, amely megfelel a $/ változóértékének. (Ez a változó $INPUT_RECORD_SEPARATOR néven is ismert az English modullal.) A levett karakterek számát adja meg. Igen gyakran használható abban az esetben, mikor a sorok végéről kell leszedni az újsor karaktert, de félsz attól, hogy az utolsó sor esetleg nincs újsor karakterrel lezárva. Ha változó nincs megadva, akkor $_ végéről veszi le az újsor karaktert. Ha paraméterként lista van megadva, akkor a lista minden egyes elemére hajtja végre a sorvégjel eltávolítást. open(F,"; close F; chomp @q; A chomp függvény bármire használható, ami balérték, így akár egy értékadásra is. chomp($cwd = `pwd`); chomp($answer = <STDIN>);
chop VARIABLE chop LIST chop Levágja a paraméterként megadott füzér utolsó karakterét, és visszaadja visszatérési értékként. Elsődleges felhasználása a sor végéről az újsor karakter leszedése, de sokkal hatékonyabb, mint a s/\n// mert se nem nézi végig, se nem másolja át a füzért. Ha a változó hiányzik, akkor $_ változót használja. while (<>) { chop; # avoid \n on last field @array = split(/:/); ... }
A Perl programozási nyelv – röviden
79/40
Mindenre alkalmazható a függvény, ami balérték, így értékadáshoz is. chop($cwd = `pwd`); chop($answer = <STDIN>); Ha argumentumként lista van megadva, akkor a lista minden egyes elemére alkalmazza az utolsó karakter levágást, de csak a legutolsó levágott karaktert adja vissza. A chop a füzér utolsó karakterét adja vissza. A többi karakter visszaadása, azaz minden karakter kivéve az utolsót a substr($string, 0, -1) függvénnyel lehetséges. chown LIST Kicseréli a fájlok tulajdonosát és csoportját. A LIST első két eleme a NUMERIKUS uid és gid ebben a sorrendben. A további elemek a fájlok nevei. A visszaadott érték a sikeresen végrehajtott műveletek száma. A legtöbb rendszeren ez a parancs csak superuser jogosultsággal hajtható végre, de elképzelhető, hogy mások számára is engedélyezett a parancs végrehajtása olyan esetben, amikor a fájl tulajdonosa csak a csoporthoz tartozást akarja kicserélni valamely másodlagos csoportra. chr NUMBER Visszatérési értéke az a karakter, amelynek a numerikus kódját paraméterként megadtuk. Például chr(65) értéke ``A'' ASCII kódtábla esetén. chroot FILENAME Ez a függvény úgy működik, mint a UNIX rendszerhívás: a paraméterként megadott könyvtár lesz minden további ``/'' jellel kezdődő fájlhivatkozás számára a gyökérkönyvtár a pillanatnyi és a gyerek processzek számára. (Az aktuális könyvtár eközben nem változik.) Biztonsági okokból ez a függvény csak a superuser számára elérhető. Ha a FILENAME nincs megadva, akkor $_-t használja a rendszer. close FILEHANDLE Bezárja a csövet, fagy fájlt, amelyhez a fájlkezelő (handle) rendelve van. A visszatérési érték TRUE, ha a bezárás sikeres volt, a pufferek ki lettek ürítve, és fájlleíró le lett zárva. Nincs szükség a fájl lezárására, ha azt rögtön követi egy ugyanarra a fájlkezelőre hivatkozó open, mivel az open lezárja a fájlt. Annyi különbség van, hogy az explicit módon végrehajtott fájl lezárás lenullázza a sorszámlálót $., míg az open által végrehajtott implicit lezárás nem. Hasonlóan, ha egy csőhöz rendelt fájlkezelőt explicit módon lezár a program, akkor a várni fog a processz lefutására, és a $? változó értékét is beállítja a processz befejezési értékére. open(OUTPUT, '|sort >foo'); # cső a sort programhoz ... # nyomtatás a csőbe close OUTPUT; # megvárja amíg a rendezés befejeződik open(INPUT, 'foo'); # elkezdjük beolvasni az eredményt (Persze ennél van hatékonyabb rendezési lehetőség is.) A FILEHANDLE lehet egy kifejezés is, amelyik a fájlkezelő nevét adja meg. closedir DIRHANDLE Bezár egy könyvtárat, amelyet a opendir-rel nyitottunk meg. connect SOCKET,NAME Megpróbál kapcsolódni egy távoli socket-hez, éppen úgy, ahogy a connect rendszerhívás teszi. Visszatérési értéke TRUE ha sikeres volt, és FALSE egyébként. A NAME egy csomag cím kell, hogy legyen amelyik a socket-nek megfelel.
A Perl programozási nyelv – röviden
79/41
continue BLOCK Ez igazából nem egy függvény, hanem egy programvezérlési kulcsszó. Ha egy BLOCK-hoz csatlakozik egy continue BLOCK, akkor ez mindig végrehajtódik, mielőtt a feltételt kiértékelné a program. Így ebbe a BLOCK-ba lehet elhelyezni azokat a programrészleteket, amelyeket akkor is végre kell hajtani, ha a ciklust a next utasítás indítja újra. cos EXPRESSION A kifejezés radiánban értelmezett érékéhez rendelt koszinusz értéket adja vissza. Ha a kifejezés hiányzik, akkor a $_ értékét használja. crypt PLAINTEXT,SALT Kódolja a PLAINTEXT füzért, pontosan úgy, ahogy a crypt C függvény feltéve, hogy a rendszeren implementálták a függvényt, és nem vették ki, mint potenciális muníciót. Ez a függvény használható a password fájl ellenőrzésére, például azért, hogy a rendszergazda ellenőrizze, hogy a felhasználók kellően bonyolult jelszót választottak. Egy kódrészlet, amelyik ellenőrzi, hogy aki a kódot futtatja tudja a saját UNIX jelszavát: $pwd = (getpwuid($<))[1]; $salt = substr($pwd, 0, 2); system "stty -echo"; print "Password: "; chop($word = <STDIN>); print "\n"; system "stty echo"; if (crypt($word, $salt) ne $pwd) { die "Sorry...\n"; } else { print "ok\n"; }
Természetesen a kulcsszavunkat megadni ismeretleneknek rettentő butaság, még akkor is ha ez az ismeretlen csupán egy program. dbmclose ASSOC_ARRAY [Ez a függvény elavult, ehelyett a tie függvény használandó.] Megszünteti a kapcsolatot a DBM fájl és a hozzá rendelt tördelőtábla között. dbmopen ASSOC,DBNAME,MODE [Ez a függvény elavult, helyette a tie használandó.] Ez a függvény hozzárendeli egy dbm(3), ndbm(3), sdbm(3), gdbm(), vagy Berkeley DB fájlt egy tördelőtáblához. ASSOC a tördelőtábla neve. Ellentétben a szokásos open függvénnyel az első argumentum nem fájl kezelő, hanem asszociatív tömb, vagy másnéven tördelőtábla. A második argumentum a fájl neve kiterjesztés nélkül. Ha a fájl nem létezik, akkor a program létrehozza a fájlt a harmadik paraméterként megadott hozzáférési MODE beállításával. (Ez az umask függvénnyel állítható.) Ha a rendszer csak a régebbi fajta DBM függvényeket támogatja, akkor egy program csak egy dbmopen utasítást hajthat végre. A Perl régebbi verzióiban, ha a rendszeren nem volt sem DBM sem pedig ndbm, a dbmopen hívása hibát generált. Jelenleg ebben az esetben sdbm(3) kerül használatra. Ha a DBM fájlhoz csak hozzáférési joga van a programnak, akkor csak olvasni fogja tudni a tördelőtábla egyes elemeit, de értéket nem adhat nekik. Ha tesztelni akarod, hogy tudod-e írni a fájlt, akkor használhatók a fájl tesztek, illetve meg lehet próbálni értéket adni a tábla egy elemének egy eval blokkon belül, amely megfogja a hibát.
A Perl programozási nyelv – röviden
79/42
Megjegyzendő, hogy az olyan függvények, mint a keys vagy values igen nagy tömböket adhatnak vissza amikor nagyméretű DBM fájlhoz rendelt tördelőtáblára alkalmazzák őket. Ehelyett inkább a each függvényt kell használni. # print out history file offsets dbmopen(%HIST,'/usr/lib/news/history',0666); while (($key,$val) = each %HIST) { print $key, ' = ', unpack('L',$val), "\n"; } dbmclose(%HIST);
defined EXPRESSION Egy logikai értéket ad vissza annak megfelelően, hogy a kifejezésnek van-e "igazi" értéke vagy nem. Sok operátor és függvény hiba esetén a undef, azaz nem definiált értéket adja vissza valamilyen hiba esetén. Ez a függvény lehetővé teszi például azt, hogy különbséget tegyünk a nulla karaktert tartalmazó és a nem definiált füzér között. A függvény használható arra is, hogy tömbök, vagy szubrutinok létét ellenőrizzük. A tördelőtáblák esetén ellenőrizhető, hogy a tördelő tábla megfelelő eleme definiált-e. Előfordulhat, hogy a tördelőtábla eleme létezik, de értéke undef ezért annak ellenőrzése, hogy a tördelőtábla eleme létezike precízebben vizsgálható a exists függvénnyel. print if defined $switch{'D'}; print "$val\n" while defined($val = pop(@ary)); die "Can't readlink $sym: $!" unless defined($value = readlink $sym); eval '@foo = ()' if defined(@foo); die "No XYZ package defined" unless defined %_XYZ; sub foo { defined &$bar ? &$bar(@_) : die "No bar"; } Az undef függvény tartozik ehhez a témához. Megjegyzés: Sokan használják a defined függvényt feleslegesen. Például a "ab" =~ /a(.*)b/; esetében a hasonlítás sikeres, és $1 értéke definiált, annak ellenére, hogy az értéke semmi, azaz nulla hosszúságú füzér. Pontosan fogalmazva, nem az az igaz, hogy $1 semminek sem felel meg a hasonlításban, hanem az, hogy $1 a semminek felel meg. delete EXPRESSION Törli a megadott értéket egy tördelő táblából. A visszatérési érték a törölt érték, vagy undef ha semmit nem törölt a rendszer. A %ENV tördelőtáblából való törlés módosítja a környezetet. Olyan tördelőtáblából való törlés, amely valamilyen DBM fájlhoz van kötve törli az elemet a tördelőtáblából. (Ugyanakkor a törlés valamilyen tie tördelőtáblából nem feltétlenül ad vissza valamilyen értéket.) A következő programrészlet az %ARRAY tördelőtábla összes elemét törli: foreach $key (keys %ARRAY) { delete $ARRAY{$key}; } (Bár gyorsabb lenne az undef használata.)
A Perl programozási nyelv – röviden
79/43
Az EXPRESSION kifejezés értéke bármi lehet feltéve, hogy az utolsó művelet efy tördelőtábla indexelés, például: delete $ref->[$x][$y]{$key};
die EXPRESSION Egy eval-on kívül kiírja a EXPRESSION tartalmát a STDERR-re (hibakimenet, általában a képernyő), és a program kilép $! hibakóddal. Ha $! értéke nulla, akkor processz kiszállási érték ($? >> 8). Ha ez az érték is nulla, akkor a kiszállási érték 255. eval kiértékelésen belül a die hatására az eval blokk nem értékelődik ki tovább, az értéke undef és az üzenet a $@ változóba kerül. Ezzel lehetőség nyílik arra, hogy die függvény kivételt okozzon. Egyenrangú példák: die "Can't cd to spool: $!\n" unless chdir '/usr/spool/news'; chdir '/usr/spool/news' or die "Can't cd to spool: $!\n"
Ha az EXPRESSION kifejezés végén nincs újsor karakter, akkor a program aktuális sorszámlálója és a bemeneti rekord számláló is hozzáadódik füzérhez. Lásd még az exit és warn függvényeket. do BLOCK Nem teljesen függvény. Végrehajtódik a BLOCK és a visszatérési érték a BOCK utolsó végrehajtott utasításának értéke. Ha egy ciklusmódosító van a végén, akkor olyan ciklust lehet létrehozni, amelyet legalább egyszer végrehajt a program. do SUBROUTINE(LIST) Ez régi, és nem használandó formája a szubrutinhívásnak. do EXPRESSION Az EXPRESSION kifejezés értékét, mint fájlnevet értelmezi, és a fájl tartalmát, mint Perl scriptet végrehajtja. Az elsődleges felhasználási terület szubrutinok beemelése a Perl könyvtárakból. A következő két példa egyenértékű: do 'stat.pl'; és eval `cat stat.pl`;
kivéve, hogy az első megoldás hatékonyabb, érthetőbb, kevésbé rendszerfüggő, figyelembe veszi az aktuális program fájlnevet a hibajelzések számára, és végigkeresi az összes -I könyvtárak a fájl megtalálásához, ha a fájl nem található meg az aktuális könyvtárban. Abban viszont teljes egészében megegyezik a két megoldás, hogy mind a kettő minden egyes alkalommal beolvassa, és a Perl interpreter értelmezi a parancsokat valahányszor az utasítás végrehajtódik, így feltehetőleg nem akarod majd végrehajtani egy ciklus belsejében. A könyvtári függvények beemelésére sokkal jobb módszer a use és require operátorok használata. dump LABEL Ez az utasítás egy azonnali dump-ot hajt végre, azaz megállítja a processzt, és egy olyan bináris fájlt hoz létre, amelyik tartalmazza a processz egész memóriaterületének tartalmát. Ennek az lehet az értelme,
A Perl programozási nyelv – röviden
79/44
hogy UNIX rendszereken az undump programmal ebből a fájlból végrehajtható bináris állományt lehet létrehozni, amelyet elindítva a program a dump utasítás utáni LABEL által meghatározott utasítással folytatódik. Ilyenkor a program első utasítása a goto LABEL minden olyan megkötéssel, amely vonatkozik a goto-ra általában. Úgy lehet elképzelni az egészet, mint egy olyan goto utasítást, amely végrehajtása közben a program meghal és azután feltámad. Minden olyan változó, amelyet a program beállított megőrzi az értékét, ugyanakkor azok a fájlok, amelyek meg voltak nyitva nem lesznek megnyitva a program újraindulásakor, és ez megzavarhatja a Perl rendszert is. Példa: #!/usr/bin/perl require 'getopt.pl'; require 'stat.pl'; %days = ( 'Sun' => 1, 'Mon' => 2, 'Tue' => 3, 'Wed' => 4, 'Thu' => 5, 'Fri' => 6, 'Sat' => 7, ); dump QUICKSTART if $ARGV[0] eq '-d'; QUICKSTART: Getopt('f');
each ASSOC_ARRAY Lista környezetben meghívva egy kételemű listát ad vissza, amely a tördelőtábla következő kulcsát, és a kulcshoz rendelt értéket adja vissza, így végig lehet menni a tábla összes elemén. Skaláris környezetben meghívva csak a következő elem kulcsát adja vissza. Az egyes elemek sorrendje nem meghatározott, és nagyban függ attól, hogy az adott Perl implementáció milyen sorrendben tárolja az egyes elemeket. Amikor már nincsen több elem nulla listát ad vissza a függvény lista környezetben, és undef értéket skaláris környezetben. Ezután a következő each hívás újra az első elemtől kezdi az iterációt. Az iteráció újraindítása csak úgy lehetséges, ha minden egyes elemen végigmegyünk. Az iteráció közben nem szabad a tördelőtáblához elemeket hozzáadni. Minden tördelőtáblához csak egy iteráló változó tartozik, és ezt használja mind a each, mind a keys, mind pedig a values függvény. A következő programdarab a környezeti változókat írja ki: while (($key,$value) = each %ENV) { print "$key=$value\n"; }
Nézd még meg a keys és values függvényeket. eof FILEHANDLE eof () eof 1-et ad visszatérési értékként ha a következő FILEHANDLE-ra vonatkozó olvasás fájlvégéhez érne, vagy ha nincs a FILEHANDLE fájlkezelőhöz nyitott fájl. FILEHANDLE lehet egy kifejezés, amely ebben az esetben a fájlkezelő nevét adja meg. Megjegyzendő, hogy ez a függvény egy karaktert olvas a fájlból, majd az ungetc C függvénnyel visszarakja az értéket. Az eof használata terminál fájlon, vagy az abból való olvasás hatására a terminál féjl elvesztheti a fájlvégjelet.
A Perl programozási nyelv – röviden
79/45
Ha nem adunk meg argumentumot az eof függvénynek, akkor azt a fájlkezelőt használja amelyet legutoljára használt olvasási utasítás. Az üres zárójelek () használata azokra a peszeudo fájlokra vonatkozik, amelyeket a parancssorban adtunk meg, így az eof() használható egy while(<>) ciklusban az utolsó fájl végének ellenőrzésére. A eof(ARGV)-t kell használni ha minden egyes fájl végét tesztelni akarjuk. Példák: # lenullázza a sorszámozást minden új fájl előtt while (<>) { print "$.\t$_"; close(ARGV) if (eof); # Nem eof() }
és # mínuszjeleket szúr be az utolsó fájl utolsó sora elé while (<>) { if (eof()) { print "--------------\n"; close(ARGV); # close vagy break; szükséges, ha a # terminálrólolvasunk } print; }
Gyakorlatilag soha nincs szükség Perl-ben az eof használatára, mert a beolvasó függvények visszatérési értéke undef ha kifutnak a beolvasható értékekből. eval EXPRESSION eval BLOCK EXPRESSION értelmezésre és végrehajtásra kerül, úgy, mintha egy kis Perl program lenne. A végrehajtás abban a környezetben történik, amelyben a pillanatnyi futás van, így minden szubrutin definíció, változóérték használható. A visszatérési érték az utolsó végrehajtott utasítás értéke, vagy a return utasítás értéke, amely éppúgy használható, mint a szubrutinok esetében. Ha szintaktikus hiba van a programrészletben, futási hiba történik, vagy egy die utasítást hajt végre a program, akkor undef értéket ad vissza a függvény és $@ tartalmazza a hibaüzenetet. Ha nem történthiba, akkor $@ garantáltan nulla hosszúságú füzér. Ha az argumentumként megadott EXPRESSION nincs megadva, akkor a függvény $_-t használja. Az utolsó pontosvessző hiányozhat a kifejezésből. Mivel a eval függvény elfogja az egyébként végzetes hibákat, még a szintaktikus hibákat is, ezért az eval függvény használható annak ellenőrzésére, hogy egyes rendszerfüggő eljárások működnek-e egy adott környezetben. Így például ellenőrizhető, hogy a socket vagy symlink függvények implementáltak-e. Az eval használható arra is, hogy a die függvénnyel kivételeket lehessen megvalósítani. Ha a kód az egyes végrehajtások között nem változik, akkor az eval BLOCK használható arra, hogy az egyes hibákat megfogja a rendszer anélkül, hogy minden egyes végrehajtáshoz a Perl újrafordítaná a kódrészletet. A hibaüzenet, ha van, ebben az esetben is $@ változóba kerül. Példák: # nullával való osztásután tovább fut a program eval { $answer = $a / $b; }; warn $@ if $@; # ugyanaz, de kevésbé hatékony eval '$answer = $a / $b'; warn $@ if $@;
A Perl programozási nyelv – röviden
79/46
# ez fordítás ideji hibát generál eval { $answer = }; # ez viszont futási időben csak $@ értékét állítja be eval '$answer ='; # sets $@ Az eval használatánál különösen oda kell figyelni arra, hogy mit is hajt végre a Perl futtató. Például eval $x; eval "$x"; eval '$x'; eval { $x }; eval "\$$x++" $$x++;
# 1. ESET # 2. ESET # 3. ESET # 4. ESET # 5. ESET # 6. ESET
Az első két változat egyenértékű, mind a kettő az $x változóban levő füzért hajtja végre, mint Perl programrészletet, annak ellenére, hogy az idézőjelek a második esetben egy kicsit félrevezetők, és a program olvasója egy kicsit megakad elgondolkodva azon, hogy vajon még mi történik itt az idézőjelek miatt (semmi). A harmadik és negyedik eset hasonló módon azonos, a végrehajtott kód $x, ami végső soron nem csinál semmit. Az ötödik eset az, amikor az idézőjelek használatának igazából értelme van, kivéve azt, hogy ebben az esetben szimbolikus referenciát is lehet használni. exec LIST Az exec rendszerfüggvény végrehajt egy rendszerparancsot, és nem tér vissza. Ha egy rendszerparancsot úgy akarunk meghívni, hogy utána a program visszatér, akkor a system függvényt kell használni. Ha több, mint egy argumentuma van a függvénynek, vagy, ha az argumentum egy tömb, amelynek több, mint egy eleme van, akkor a rendszer az execvp(3) rendszerhívást hajtja végre, a LIST argumentumokkal. Ha csak egy skalár argumentuma van a függvénynek, akkor ezt a rendszer shell metakarakterek szempontjából ellenőrzi. Ha van ebben shell metakarakter, akkor az egész argumentumot átadja a rendszer a /bin/sh -c paranccsal a rendszernek. Ha nincsenek metakarakterek, akkor az argumentum szavakra lesz bontva, és az így keletkezett szó lista kerül direkt módon az execvp() rendszerhívásba. Sem az exec, sem pedig a system függvények nem söprik ki a kimeneti puffereket, ezért érdemes $| változót beállítani, hogy ne vesszen el kimenet. Példák: exec '/bin/echo', 'Your arguments are: ', @ARGV; exec "sort $outfile | uniq"; Ha hazudni akarsz a végrehajtandó programnak a nevét illetően, akkor a lista elé indirekt objektumként, vessző nélkül lehet beírni a végrehajtandó parancsot. Ebben az esetben az argumentumokat minden esetben listaként értelmezi a Perl, még abban az esetben is, ha csak egy skalár érték szerepel a listában. Példák: $sh = '/bin/csh'; exec $sh '-sh'; # nézzen ki úgy, mint egy login shell vagy direktebb módon: exec {'/bin/csh'} '-sh'; # nézzen ki úgy, mint egy login shell exists EXPRESSION
A Perl programozási nyelv – röviden
79/47
Visszatérési értéke TRUE, ha a megadott tördelőtábla elem létezik, még abban az esetben is, ha annak értéke undef. Példa: print "Exists\n" if exists $array{$key}; print "Defined\n" if defined $array{$key}; print "True\n" if $array{$key}; Egy elem lehet TRUE, ha definiált, és definiált, ha létezik, de a fordított állítás nem feltétlenül igaz. A kifejezés tetszőlegesen bonyolult lehet, feltéve, hogy az utolsó művelet egy tördelőtábla keresés, például if (exists $ref->[$x][$y]{$key}) { ... } exit EXPRESSION Kiértékeli az EXPRESSION kifejezést, és ennek értékével kilép a programból. Ha definiálva van bármilyen END függvény, akkor ezeket hívja először, de ezek nem tudják az exit függvényt megállítani. Hasonlóan az objektum lebontók, amelyeket meg kell hívni meghívódnak a kifejezés kiértékelése előtt. Ha az EXPRESSION hiányzik, akkor a kilépési érték nulla. Példa: $ans = <STDIN>; exit 0 if $ans =~ /^[Xx]/; Hasonló függvény: die. exp EXPRESSION Kiszámítja az eEXPRESSION értéket, ahol e a természetes logaritmus alapszáma. Ha EXPRESSION nincs megadva, akkor az exp($_) értéket számítja ki. fcntl FILEHANDLE,FUNCTION,SCALAR A UNIX rendszerek fcntl függvényét valósítja meg. Feltehetőleg ennek használatához a use Fcntl; parancsot kell használnod a korrekt függvénydefiníciók eléréséhez. Az argumentumok kezelése éppen úgy történik, mint a ioctl függvénynél. Az fcntl minden olyan gépen, amelyen nincsen implementálva a fcntl rendszerfüggvény fatális hibát generál. Példa: use Fcntl; fcntl($filehandle, F_GETLK, $packed_return_buffer); fileno FILEHANDLE Visszaadja a fájl leírót egy fájl kezelőhöz. Ez akkor lehet különösen kellemes amikor bittérképet kell készíteni a select függvényhez. Ha a FILEHANDLE egy kifejezés, akkor ennek értéke adja meg a fájlkezelő nevét. flock FILEHANDLE,OPERATION Meghívja a flock rendszerfüggvényt a FILEHANDLE által kezelt fájlra. A rendszerdokumentáció flock(2)manuál oldalán olvasható, hogy OPERATION pontosan milyen értékek esetén mit csinál. Az olyan rendszereken, ahol sem az flock sem pedig az fcntl nincs implementálva fatális hibát generál (például Windows95). Ha egy rendszeren az flock nincs implementálva, de az fcntl igen, akkor automatikusan ezt hívja meg a Perl program. Ezzel az flock hordozható fájl lezárási módszer, de egész fájlokat lehet csak lezárni vele, nem rekordokat. Egyes rendszereken az flock nem működik hálózaton keresztüli fájlokra, ilyenkor a sokkal rendszerfüggőbb fcntl használandó.
A Perl programozási nyelv – röviden
79/48
Egy egyszerű példa, amely egy BSD rendszerben a mailbox-hoz fűz hozzá: $LOCK_SH = 1; $LOCK_EX = 2; $LOCK_NB = 4; $LOCK_UN = 8; sub lock { flock(MBOX,$LOCK_EX); # és ha esetleg valaki írt a fájl végéhez # amíg vártunk... seek(MBOX, 0, 2); } sub unlock { flock(MBOX,$LOCK_UN); } open(MBOX, ``>>/usr/spool/mail/<STRONG>$ENV{'USER'}'') or die ``Can't open mailbox: $!''; lock(); print MBOX $msg,"\n\n"; unlock(); fork Végrehajt egy fork(2) rendszerhívást. A gyerek pid (processz azonosító) a visszatérési értéke az apa processzben, és 0 a gyerek processzben, vagy undef ha a fork sikertelen. A kitakarítatlan pufferek azok maradnak mind a két processzben, így $| értékének beállítása vagy az autoflush meghívása szükséges a dupla műveletek elkerülése érdekében. Ha a fork függvényt úgy hívod meg, hogy nem vársz a gyermek processzre, akkor zombikat generálsz: $SIG{CHLD} = sub { wait }; Egy mási dupla fork trükk: unless ($pid = fork) { unless (fork) { exec "amit csak végre akarunk hajtani"; die "nincs exec"; # ... vagy ... ## (Perl kód jön ide) exit 0; } exit 0; } waitpid($pid,0); format Deklarál egy nyomtatási képformátumot, amelyet azután a write függvény használ. Például: format Something = Test: @<<<<<<<< @||||| @>>>>> $str, $%, '$' . int($num) . $str = "widget"; $num = $cost/$quantity; $~ = 'Something';
A Perl programozási nyelv – röviden
79/49
write;
formline PICTURE, LIST Ez egy belső függvény, amelyet a format hív meg, de amelyet meghívhat a Perl program is. Egy sor értéket formáz meg a PICTURE formátumnak megfelelően, és az eredményt a format kimenet gyűjtőbe $^ helyezi el. Tulajdonképpen amikor egy write függvényhívás történik a $^ tartalma íródik ki egy fájlba. getc FILEHANDLE getc Visszaadja a következő karaktert a FILEHANDLE fájlkezelőhöz rendelt fájlból, vagy nulla füzért ad vissza a fájl végén. Ha nincs megadva fájlkezelő, akkor a szabványos bemenetről olvas. Ez a függvény nem túl hatékony, és ugyanakkor nem használható nem pufferelt egyedi karakterek beolvasására sem. Ehhez valami ilyesmire van inkább szükség: if ($BSD_STYLE) { system "stty cbreak /dev/tty 2>&1"; } else { system "stty", '-icanon', 'eol', "\001"; } $key = getc(STDIN); if ($BSD_STYLE) { system "stty -cbreak /dev/tty 2>&1"; } else { system "stty", 'icanon', 'eol', '^@'; # ascii null } print "\n";
getlogin Az aktuális login értéket adja vissza az /etc/utmp fájlból. Ha nulla, akkor a getpwuid függvényt kell használni, $login = getlogin || (getpwuid($<))[0] || "Verhas"; Ugyanakkor a getlogin függvény nem ajánlott autentikációs feladatokhoz, mert nem elegendően biztonságos. getpeername SOCKET Visszaadja a csomag sockaddr címét a SOCKET kapcsolat másik végének. use Socket; $hersockaddr = getpeername(SOCK); ($port, $iaddr) = unpack_sockaddr_in($hersockaddr); $herhostname = gethostbyaddr($iaddr, AF_INET); $herstraddr = inet_ntoa($iaddr); getpgrp PID Visszaadja a pillanatnyi processz csoportot a megadott PID-hez. Ha a PID nulla, vagy nincs megadva akkor a program processzhez adja meg a csoportot. Hibát generál olyan gépeken, ahol a getpgrp(2) rendszerhívás nincs implementálva. A POSIX verziója a getpgrp() függvénynek csak az aktuális processzhez mondja meg a csoportot, ezért a getpgrp használata csak PID==0 esetén hordozható. getppid Az apa processz azonosítóját adja vissza.
A Perl programozási nyelv – röviden
79/50
getpriority WHICH,WHO Az aktuális processz, processz csoport vagy felhasználó prioritását adja vissza. Fatális hibát okoz olyan gépeken, ahol a getpriority rendszerhívás nincs implementálva. getpwnam NAME getgrnam NAME gethostbyname NAME getnetbyname NAME getprotobyname NAME getpwuid UID getgrgid GID getservbyname NAME,PROTO gethostbyaddr ADDR,ADDRTYPE getnetbyaddr ADDR,ADDRTYPE getprotobynumber NUMBER getservbyport PORT,PROTO getpwent getgrent gethostent getnetent getprotoent getservent setpwent setgrent sethostent STAYOPEN setnetent STAYOPEN setprotoent STAYOPEN setservent STAYOPEN endpwent endgrent endhostent
A Perl programozási nyelv – röviden
79/51
endnetent endprotoent endservent Ezek a függvények pont azt teszik, mint a megfelelőik a rendszerkönyvtárban. Lista környezetben a visszatérési értékek csoportonként különböznek a következők szerint: ($name,$passwd,$uid,$gid, $quota,$comment,$gcos,$dir,$shell) = getpw* ($name,$passwd,$gid,$members) = getgr* ($name,$aliases,$addrtype,$length,@addrs) = gethost* ($name,$aliases,$addrtype,$net) = getnet* ($name,$aliases,$proto) = getproto* ($name,$aliases,$port,$proto) = getserv* Ha a megfelelő elem nem létezik, akkor nulla listát ad vissza a rendszer. Skalár környezetben a nevet adja vissza a rendszer, kivéve, ha függvény éppenséggel név szerinti keresésre irányul. Ekkor éppen a másik dolgot adja vissza a függvény, bármi legyen is az a másik dolog. Ha a megfelelő elem nem létezik, akkor undef értéket ad vissza a rendszer. Például: $uid = getpwnam $name = getpwuid $name = getpwent $gid = getgrnam $name = getgrgid $name = getgrent stb. A $members érték amit a getgr* függvények visszadnak a csoporthoz tartozó felhasználók login neveit adják meg egy füzérben szóközzel elválasztva. A gethost*() függvények, amennyiben a C rendszer támogatja a h_errno változót ennek értékét a $? változóban adják vissza. A @addrs változó, amelyet a sikeres hívás ad vissza a nyers címeket tartalmazzák, amelyeket a a megfelelő rendszerfüggvény adott vissza. Az Internet tartományban minden ilyen cím négy bájt hosszú és kicsomagolható egy ($a,$b,$c,$d) = unpack('C4',$addr[0]); paranccsal. getsockname SOCKET A távolis Socket kapcsolat csomag sockaddr címét adja vissza. use Socket; $mysockaddr = getsockname(SOCK); ($port, $myaddr) = unpack_sockaddr_in($mysockaddr); getsockopt SOCKET,LEVEL,OPTNAME Visszaadja a kért socket opciókat, és undef ha valamilyen hiba történt. glob EXPRESSION Visszaadja a fájl nevét a megfelelő joker karakter kiegészítéssel, úgy ahogy azt a shell tenné. Ez a belő függvény, amelyet a <*.*> operátor használ. gmtime EXPRESSION
A Perl programozási nyelv – röviden
79/52
Átkonvertálja az argumentumként megadott időt (amelyet a time függvényből nyerünk) egy kilenc elemű listává. Ez az idő nem lesz lokalizálva, azaz a greenwichi középidőt adják meg a tömb egyes elemei. A tipikus felhasználás: ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time); Az összes listaelem numerikus, és direkt módon a struct tm rekordból kerülnek ki. Másszavakkal ez azt jelenti, hogy $mon nulla és 11 között lesz, $wday nulla és 6 között. Ha nincs EXPRESSION megadva, akkor gmtime(time()) kerül kiszámításra. goto LABEL goto EXPRESSION goto &NAME A goto LABEL forma megkeresi azt az utasítást, amely a LABEL címkével van megjelölve, és ennél az utasításnál folytatja a futást. Nem használható bármilyen olyan programstruktúrába való beugrásba, amely valamilyen inicializálást kíván, mint szubrutin, vagy foreach hurok. Akkor sem szabad ilyen struktúrába belelépni ezzel az utasítással, ha azt a Perl értelmező kioptimalizálta. Gyakorlatilag bárhova el lehet ugrani a dinamikus kereteken belül, akár ciklusból vagy szubrutinból ki is. Ugyanakkor ezekre alkalmasabb valamely más konstrukció, például last vagy die. A goto EXPRESSION azt várja, hogy a kifejezés értéke egy cimke legyen, amelyet a kifejezés kiértékelése után megkeres a Perl értelmező, és onnan folytatja a futást. Ez olyan kiszámított goto lehetőséget ad, mint amilyent egyesek FORTRAN-ban szokhattak meg, de nem ajánlott a használata. A gotot &NAME forma meghívja a NAME szubrutint, de amikor az visszatér akkor nem a goto utasítás után folytatódik a futás, hanem ott ahol ahonnan a goto-t tartalmazó szubrutint meghívták. Más szavakkal ez a goto olyan, mint egy szubrutinhívás, amelyet rögtön követ egy return utasítás, azzal a különbséggel, hogy a hívott szubrutin ebben az esetben más vermet, és más hívótlát (caller). Ezt az utasítást általában a modulok AUTOLOAD szubrutinjai használják, amelyek futási időben, akkor töltenek be egyes szubrutinokat, amikor azokra a hivatkozás történik, majd úgy hívja meg azokat, mintha rögtön azokat hívta volna meg a program (kivéve, hogy minden módosítás, amely a @_ változón történik a hívott félnél megmarad). A goto után a még a caller függvény sem tudja megmondani, hogy nem ez a szubrutin volt elsőként meghívva. grep BLOCK LIST grep EXPRESSION,LIST Végrehajtja a BLOCK vagy EXPRESSION blokkot, illetve kifejezést a LIST lista minden elemére (helyileg beállítva $_ értékét az egyes elemekre és visszaad egy olyan listát, amely tartalmazza azokat az elemeket, amelyekre a BLOCK vagy EXPRESSION értéke TRUE. Skaláris környezetben azt adja meg, hogy hányszor volt a kifejezés értéke TRUE. @foo = grep(!/^#/, @bar); # kitöröljük a megjegyzéseket # ekvivalens módon @foo = grep {!/^#/} @bar; # ugyanezt csinálja Mivel $_ referenciaként kerül beállításra, ezért használható arra, hogy a lista egyes elemeit módosítsa a grep függvény, de ez igen bizarr eredményeket adhat abban az esetben, amikor a LIST lista nem egy névvel hivatkozott tömb. hex EXPRESSION
A Perl programozási nyelv – röviden
79/53
Az EXPRESSION kifejezést, mint hexadecimálisan megadott füzért értelmezi, és a numerikus értéket adja vissza. Az olyan számok értelmezésére, amelyek vagy 0x karakterekkel kezdődnek az oct függvény használható. Ha EXPRESSION nincs megadva, akkor $_ értékét használja a függvény. import Nincs igazi, beépített import függvény. Sokkal inkább ilyen néven kell definiálni egy modulon belül azt a szubrutint amelyek a szimbólumtábla importját végzik. Ez az a szubrutin, amelyet a use függvény hív meg. index STR,SUBSTR,POSITION index STR,SUBSTR Visszaadja a SUBSTR füzér STR füzérbeli első előfordulási helyének az indexét a POSITION pozíciónál, vagy az után. Ha nincs megadva pozíció, akkor a füzér elejétől kezdi a keresést. A visszatérési érték nullától indul (illetve attól az értéktől amire $[ be lett állítva, de jobb ilyet nem tenni), másképp fogalmazva az első karakter indexe nulla, a másodiké egy stb. Ha a füzér nem található meg, akkor visszatérési érték -1, pontosabban fogalmazva $[-1. int EXPRESSION Az EXPRESSION kifejezés egészrészét adja vissza. Ha nincs megadva argumentum, akkor $_ egészrészét adja vissza. ioctl FILEHANDLE,FUNCTION,SCALAR Az ioctl(2) rendszerfüggvényt valósítja meg. Ennek használata előtt feltehetőleg a require "ioctl.ph"; # probably in /usr/local/lib/perl/ioctl.ph sorral be kell emelni a függvény definícióját. Ha ez a fájl nem létezik az adott rendszeren, akkor nem marad más, mint a megfelelő C fejléc fájlok alapján előállítani, de ez nem triviális. SCALAR értékét fogja a függvény írni, illetve olvasni a FUNCTION függvénynek megfelelően. Ha SCALAR füzér, akkor a rendszerfüggvény a füzérre mutató mutatót ad át, míg ha értéke numerikus, akkor magát a numerikus értéket. Hogy biztos legyen, hog egy érték numerikus előtte adjunk hozzá nullát. A pack és unpack függvények nagyon hasznosak lehetnek az ioctl függvény által kezelt struktúrák manipulálásához. A következő példa a DEL karaktert állítja törlő karakterré: require 'ioctl.ph'; $getp = &TIOCGETP; die "NO TIOCGETP" if $@ || !$getp; $sgttyb_t = "ccccs"; # 4 chars and a short if (ioctl(STDIN,$getp,$sgttyb)) { @ary = unpack($sgttyb_t,$sgttyb); $ary[2] = 127; $sgttyb = pack($sgttyb_t,@ary); ioctl(STDIN,&TIOCSETP,$sgttyb) || die "Can't ioctl: $!"; } Az ioctl és fcntl függvények visszatérési értéke a következő: az operációs rendszer a Perl visszatérési értéke visszatérési értéke -1 undef 0 füzér "0 de TRUE" bármi más szám maga a szám
A Perl programozási nyelv – röviden
79/54
Így a Perl függvény visszatérési értéke TRUE siker esetén, és FALSE hiba esetén, mégis lehetőség van megnézni, hogy az operációs rendszer milyen értéket adott vissza. ($retval = ioctl(...)) || ($retval = -1); printf "System returned %d\n", $retval; join EXPRESSION,LIST A LIST listában szereplő füzéreket fűzi össze egy füzérré az EXPRESSION kifejezés által megadott füzérrel, mint elválasztóval. Például: print join('|' , (1,2,3,5,6,7,9,"kurtavas")); kimenete 1|2|3|5|6|7|9|kurtavas Az ellentétes hatású függvény, amely egy füzért szétbont listává a split. keys ASSOC_ARRAY A visszatérési értéke egy tömb, amely tartalmazza az argumentumként megadott tördelőtábla kulcsait. Skaláris környezetben a kulcsok számát adja meg. A sorrend, ahogy a kulcsok szerepelnek a tömbben nem rendezett, de garantáltan ugyanaz a sorrend, ahogy az egyes elemeket a values illetve az each adja vissza, feltéve, hogy két ilyen függvényhívás között nem változott meg a tördelőtábla. Egy újabb példa a környezeti változók kiírására: @keys = keys %ENV; @values = values %ENV; while ($#keys >= 0) { print pop(@keys), '=', pop(@values), "\n"; }
és a környezeti változók azon a gépen, ahol e dokumentum HTML-re fordítása történt: SYSTEMDRIVE=E: PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.JS OS2LIBPATH=E:\WINNT4\system32\os2\dll; PROCESSOR_LEVEL=5 LIB=D:\Program Files\Mts\Lib USERDOMAIN=DECINT LOGONSERVER=\\CELEBRIS HOMEPATH=\ TEMP=E:\TEMP TMP=E:\TEMP COMPUTERNAME=CELEBRIS USERPROFILE=E:\WINNT4\Profiles\verhas NUMBER_OF_PROCESSORS=1 PROCESSOR_REVISION=0205 PATH=C:\Perl5\bin;E:\WINNT4\system32;E:\WINNT4;;E:\MSSQL\BINN;;D:\Program Files\Mts;C:\DOS WINDIR=E:\WINNT4 COMSPEC=E:\WINNT4\system32\cmd.exe SYSTEMROOT=E:\WINNT4 INCLUDE=D:\Program Files\Mts\Include HOMEDRIVE=E: OS=Windows_NT PROCESSOR_ARCHITECTURE=x86 PROCESSOR_IDENTIFIER=x86 Family 5 Model 2 Stepping 5, GenuineIntel PROMPT=$P$G
A Perl programozási nyelv – röviden
79/55
USERNAME=verhas kill LIST Jelzést (signal) küld a LIST listában szereplő processzeknek. A LIST lista első eleme a jelzés értéke, a további elemek a processz azonosítók. A visszatérési érték a sikeres jelküldések száma. $cnt = kill 1, $child1, $child2; kill 9, @goners;
A shell-lel ellentétben, Perl-ben ha a jel értéke negatív, akkor processz csoportoknak küldi a kill a jelet. (A System V rendszereken is így van, az azonban nem hordozható, Perl-ben minden rendszeren így van, ahol a kill függvény implementált.) Ez azt jelenti, hogy általában pozitív értékeket kell használni. Használhatók a jelek nevei aposztrófok között is. last LABEL last A last nem függvény, hanem egy utasítás. A hatása hasonló a C programozási nyelvbeli break utasításhoz. Hatására a program azonnal abbahagyja a ciklus végrehajtását. Ha a LABEL címke nincs megadva, akkor a legbelső ciklus futását szakítja meg a program, ha LABEL meg van adva, akkor azt a ciklust szakítja meg, amelyre a címke vonatkozik. A program futása a parancs végrehajtásának hatására a ciklus utáni utasításon folytatódik. continue blokk nem hajtódik végre. $i = 7; CIKLI: while(1){ $j = 1; while(1){ last if $j == 3 && $i < 9 ; last CIKLI if $j == 3; print $i,$j++ ; } $i++; }
és a kimenete: 717281829192 lc EXPRESSION Az EXPRESSION kifejezés, mint füzér kisbetűs alakját adja vissza. Ez az a belső függvény, amelyet a \L escape szekvencia használ. Elvileg figyelembe kell vennie minden POSIX setlocale() beállítást. lcfirst EXPRESSION Az EXPRESSION kifejezés, mint füzért adja vissza, úgy, hogy az első karakter kisbetűs. Ez az a belső függvény, amelyet a \l escape szekvencia használ. Elvileg figyelembe kell vennie minden POSIX setlocale() beállítást. length EXPRESSION Az EXPRESSION kifejezés, mint füzér karakterekben mért hosszát adja vissza. Ha az EXPRESSION nincs megadva, akkor $_-t használja. link OLDFILE,NEWFILE Létrehoz egy új fájlnevet NEWFILE néven, amelyet a régi fájlhoz OLDFILE kapcsol. A visszatérési értéke 1 siker esetén, és 0 egyébként. Windows NT alatt nincs implementálva. listen SOCKET,QUEUESIZE
A Perl programozási nyelv – röviden
79/56
Ugyanazt teszi, mint az azonos nevű rendszerhívás. Visszatérési értéke TRUE siker esetén, és FALSE egyébként. local LIST A local nem egy függvény, hanem egy Perl utasítás, amely a LIST listában felsorolt változókat teszi lokálissá egy szubrutin, eval vagy do blokk erejéig. Ez a lokalitás azonban nem olyan, mint amit PASCAL, C vagy bármilyen más programozási nyelvben megszokhattunk. A local által adott lokalitás futási idejű, és nem grammatikai. A grammatikai lokalitást a my utasítás adja. Részletes leírás található a szbrutinokról szóló fejezetben. localtime EXPRESSION Átkonvertálja az argumentumként megadott időt (amelyet a time függvényből nyerünk) egy kilencelemű listává. A megadott idő helyi idő lesz. A tipikus felhasználás: ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); Az összes listaelem numerikus, és direkt módon a struct tm rekordból kerülnek ki. Másszavakkal ez azt jelenti, hogy $mon nulla és 11 között lesz, $wday nulla és 6 között. Ha nincs EXPRESSION megadva, akkor gmtime(time()) kerül kiszámításra. Skalár környezetben füzérként írja ki az időt a ctime(3) rendszerhívásnak megfelelően. $a =localtime; print $a; Mon Jul 6 09:57:29 1998 log EXPRESSION Az argumentumként megadott EXPRESSION kifejezés természetes alapú logaritmusát számítja ki és adja vissza értékként. Ha EXPRESSION kifejezés nincs megadva, akkor $_-t használja a program. lstat FILEHANDLE lstat EXPRESSION Ugyanazt teszi, mint a stat függvény, de nem a fájl paramétereit vizsgálja meg, hanem a szimbolikus linkét. Ha a szimbolikus linkek nincsenek implementálva a rendszeren, akkor ugyanaz a hatása, mint a statnak. m// A mintaillesztési operátor. Részletesen a reguláris kifejezések fejezetben. map BLOCK LIST map EXPRESSION,LIST Kiértékeli a BLOCK blokkot, vagy az EXPRESSION kifejezést a LIST lista minden egyes elemére, úgy, hogy közben $_ tartalmazza az éppen aktuális listaelemet. A visszatérési érték egy lista, amely az egyes kiértékelések eredményeiből adódik. A kiértékelés minden egyes ciklusban listakörnyezetben zajlik, így egy-egy kiértékelés több, mint egy listaelemet is eredményezhet, a végső lista ezeknek az összefűzéséből fog adódni. @chars = map(chr, @nums); számok listáját konvertálja a megfelelő karakterekké. %hash = map { getkey($_) => $_ } @array; ugyanaz, mint %hash = (); foreach $_ (@array) {
A Perl programozási nyelv – röviden
79/57
$hash{getkey($_)} = $_; } mkdir FILENAME,MODE Létrehozza a FILENAME könyvtárak a megadott hozzáférési móddal. Ha a művelet sikeres a visszatérési érték 1, ha nem akkor 0 és $! tartalmazza a hibaüzenetet. msgctl ID,CMD,ARG Meghívja a System V IPC msgctl(2) függvényt. Ha CMD &IPC_STAT, akkor ARG egy változó kell, hogy legyen, amelyik tartalmazza a visszaadott msqid_ds struktúrát. A visszatérési érték az ioctl-hez hasonlóan undef hiba esetén és "0 de TRUE" zero esetén, illetve az aktuális érték egyébként. msgget KEY,FLAGS Meghívja a System V IPC msgget(2) függvényt. A visszatérési érték az üzenetsor azonosító, illetve undef hiba esetén. msgsnd ID,MSG,FLAGS Meghívja a System V IPC msgsnd függvényt az MSG üzenet elküldésére az ID azonosítójú üzenetsorba. Az MSG üzenetnek egy hosszú egész (long int) számmal kell kezdődnie, amelyet például a pack('l',$type) függvénnyel lehet létrehozni. A visszatérési érték TRUE siker esetén, és FALSE egyébként. msgrcv ID,VAR,SIZE,TYPE,FLAGS Meghívja a System V IPC msgrcv függvényt, hogy az ID azonosítójú üzenetsorból üzenetet kapjon a VAR változóba, maximum SIZE méretben. Amennyiben üzenet érkezik, az első dolog a VAR változóban az üzenet típusa lesz és a VAR változó mérete SIZE plusz az üzenet típus mérete. A visszatérési érték TRUE siker esetén és FALSE egyébként. my EXPRESSION A my nem egy függvény, hanem egy Perl utasítás, amely a LIST listában felsorolt változókat teszi lokálissá egy szubrutin, eval vagy do blokk erejéig. Ez a lokalitás olyan, mint amit PASCAL, C vagy bármilyen más programozási nyelvben megszokhattunk ellentétben a local utasítással. Részletes leírás található a szbrutinokról szóló fejezetben. next LABEL next A next egy olyan ciklusutasítás, amelynek hatására a ciklus újraindul úgy, mint a C programozási nyelvben a continue hatására. Ha a ciklushoz van continue blokk, akkor az ebben található utasítások végrehajtónak a next hatására, mielőtt a ciklus újraindulna. Ha nincs megadva LABEL címke, akkor az utasítás a legbelső ciklusra vonatkozik. no Module LIST A use függvény ellentéte. oct EXPRESSION Az EXPRESSION kifejezést, mint oktális füzért értelmezi, és az értékét adja vissza. Ha a füzér éppen 0x karakterekkel kezdődik, akkor hexadecimális értékként értelmezi. A következő sor mind a decimális, mind az oktális, mind pedig a hexadecimális számokat megfelelően konvertálja, amennyiben azok a C szintaxisnak (ami Perl-ben ugyanaz) megfelelnek: $val = oct($val) if $val =~ /^0/;
Ha EXPRESSION nincs megadva, akkor $_-t használja a rendszer. open FILEHANDLE,EXPRESSION open FILEHANDLE Megnyit egy fájlt, amelynek a nevét az EXPRESSION tartalmazza, és hozzárendeli a FILEHANDLE fájlkezelőhöz. Ha FILEHANDLE helyén egy kifejezés van, akkor ennek az értékét fogja használni, mint a fájlkezelő nevét. Ha az EXPRESSION kifejezés hiányzik, akkor a skaláris változó, amelynek ugyanaz a
A Perl programozási nyelv – röviden
79/58
neve, mint a FILEHANDLE fájlkezelőnek tartalmazza a fájl nevét. Ha a fájlnév < karakterrel kezdődik akkor olvasásra nyitja meg a rendszer a fájlt. (Egyébként ez az alapviselkedés, ha tehát a következők egyikének sem felel meg a szintaxis, akkor is olvasásra nyitja meg a fájlt.) Ha a fájlnév > karakterrel kezdődik, akkor írásra nyitja meg. Ha a fájlnév kezdete >> akkor hozzáírásra nyitja meg a fájlt (írásra a végére pozícionálva, így hozzáír a fájlhoz). Egy + jel kerülhet a < vagy > jel elé a mind írásra, mind pedig olvasásra való megnyitáshoz. Általában a +< a szokásos írás/olvasás megnyitási forma, mivel a +> a fájlt először törli. Ezek megfelelnek a fopen(3) rendszerhívás 'r', 'r+', 'w', 'w+', 'a', és 'a+' módjainak. Ha a fájlnév egy | karakterrel kezdődik, akkor a fájlnevet a rendszer mint parancsot értelmezi amelynek bemenete a cső, ha pedig az utolsó karakter, akkor olyan parancsként értelmezi a rendszer amelynek kimenetéből olvasunk. Olyan open() parancsot nem lehet kiadni, amelyikbe írunk is és olvasunk is belőle. - megnyitása a szabványos bemenet megnyitását jelenti, és >- megnyitása a szabványos kimenet. Siker esetén a függvény visszatérési értéke nem nulla, hiba esetén undef. Ha a fájl történetesen egy cső, akkor a visszatérési érték az alprocessz PID-je. Ha olyan rendszeren használod a Perl-t, amelyik különbséget tesz bináris és text fájlok között, akkor érdemes használni a binmode függvényt. A lényegi különbség a text fájlok sorvégjelölésében van. $ARTICLE = 100; open ARTICLE or die "Can't find article $ARTICLE: $!\n"; while () {... open(LOG, '>>/usr/spool/news/twitlog'); # (log is reserved) open(DBASE, '+/tmp/Tmp$$"); # $$ is our process id # feldolgozzuk a fájlokat, és minden include fájlt foreach $file (@ARGV) { process($file, 'fh00'); } sub process { local($filename, $input) = @_; $input++; #ez füzér növelés!! unless (open($input, $filename)) { print STDERR "Can't open $filename: $!\n"; return; } while (<$input>) { # note use of indirection if (/^#include "(.*)"/) { process($1, $input); next; } ... # bármilyen kód } }
A Perl programozási nyelv – röviden
79/59
A Bourne shell hagyományainak megfelelően ha a fájlnév >& karakterekkel kezdődik, akkor a füzér további része, mint a fájlkezelő neve értelmeződik, és ez lesz megduplázva és megnyitva. Az & karakter használható >, >>, <, +>, +>> és +< után. A módnak ugyanannak kell lenni, mint az eredeti fájlnál. Itt egy rövid script, amely elmenti, átirányítja, és visszaállítja az STDOUT és STDERR-t: #!/usr/bin/perl open(SAVEOUT, ">&STDOUT"); open(SAVEERR, ">&STDERR"); open(STDOUT, ">foo.out") || die "Can't redirect stdout"; open(STDERR, ">&STDOUT") || die "Can't dup stdout"; select(STDERR); $| = 1; # make unbuffered select(STDOUT); $| = 1; # make unbuffered print STDOUT "stdout 1\n"; # this works for print STDERR "stderr 1\n"; # subprocesses too close(STDOUT); close(STDERR); open(STDOUT, ">&SAVEOUT"); open(STDERR, ">&SAVEERR"); print STDOUT "stdout 2\n"; print STDERR "stderr 2\n"; Ha a fájlnév <&= karakterekkel kezdődik, akkor a Perl a C nyelv fdopen függvényének megfelelően működik. Ha egy csövet (pipe) nyitunk meg a - fájlnévre, akár |- akár pedig -| formában, akkor implicit módon egy fork hajtódik végre. Az open visszatérési értéke ebben az esetben a gyermek processz PID-je az apában és 0 a gyerekben. (Ilyenkor az open értéke helyett a defined függvénnyel kell megvizsgálni, hogy sikeres volt-e a megnyitás.) Az apában a fájlkezelő normálisan lesz megnyitva, és az írás/olvasás a gyermek processz felé halad/onnan jön. A gyerekben a fájlkezelő nem lesz megnyitva, az írás és olvasás a szabványos bemeneten és kimeneten kell, hogy történjen. A close meghívása bármely csőre a gyermek processz végére való várakozást jelenti és a visszatérési érték $? változóba kerül. Minden olyan operációs esetén, amelyik fork-ot hajt végre, a kiürítetlen pufferek kiürítetlenek maradnak, ezért ezekre a $| értékét 1-re kell állítani. A FileHandle csomag használatával lehetőség van olyan fájlkezelő nevek kialakítására, amelyek ugyanolyan környezetben használhatók, mint a rájuk hivatkozó változók, és automatikusan bezárja őket a rendszer, amikor minden hivatkozás megszűnik a fájlra: use FileHandle; ... sub read_myfile_munged { my $ALL = shift; my $handle = new FileHandle; open($handle, "myfile") or die "myfile: $!"; $first = <$handle> or return (); # automatikusan bezárja itt mung $first or die "mung failed"; # vagy itt return $first, <$handle> if $ALL; # vagy itt $first; # vagy itt }
A Perl programozási nyelv – röviden
79/60
A fájlnévből, amelyet az open megkap a bevezető és a lezáró szóközöket kitörli. Emiatt, ha olyan fájlt akarsz megnyitni, amely bevezető, vagy lezáró szóközöket tartalmaz, ezeket meg kell védeni. Ennek egy lehetséges módja: $file =~ s#^(\s)#./$1#; open(FOO, "< $file\0"); Ha igazi C open-t szeretnél, akkor a sysopen függvényt kell használni. Ez egy másik lehetőség a fájlnév teljes megvédésére, például use FileHandle; sysopen(HANDLE, $path, O_RDWR|O_CREAT|O_EXCL, 0700) or die "sysopen $path: $!"; HANDLE->autoflush(1); HANDLE->print("stuff $$\n"); seek(HANDLE, 0, 0); print "A fájl tartalma: ", ; Érdemes még a seek függvényt is megtanulni ahhoz, hogy hogyan lehet az olvasást, és az írást keverni. opendir DIRHANDLE,EXPRESSION Az EXPRESSION kifejezés által megadott nevű könyvtárat nyitja meg, hogy a readdir, telldir seekdir rewinddir és closedir függvényekkel hozzá lehessen férni a fájlnevekhez. Visszatérési értéke TRUE siker esetén és FALSE egyébként. A DIRHANDLE könyvtárkezelő külön névterületen van nyilvántartva, elkülönítve a fájlkezelőktől, így egy könyvtárkezelőnek lehet ugyanaz a neve, mint egy fájlkezelőnek. ord EXPRESSION Az EXPRESSION által adott füzér első karakterének ASCII kódját adja vissza. Ha nincs argumentum megadva, akkor $_ értékét veszi. pack TEMPLATE,LIST Sorba veszi a LIST lista elemeit, és egy bináris értéket alkot belőlük a TEMPLATE füzérnek megfelelően értelmezve a LIST lista egyes elemeit. A TEMPLATE-ben az egyes karakterek jelentése: A ASCII füzér szóközökkel kiegészítve. a ASCII füzér nulla karakterekkel kiegészítve. b bit füzér növekvő bit sorrendben, mint a vec függvénynél. B bit füzér csökkenő bit sorrendben. h hexadecimális füzér alacsony helyérték először. H hexadecimális füzér magas helyérték először. c előjeles karakter érték. C előjel nélkülikarakter érték. s előjeles rövid egész. S előjel nélküli rövid egész. i előjeles egész. I előjel nélküli egész. l előjeles hosszú egész. L előjel nélklüli hosszú egész. n rövid egész "hálózati" sorrendben. N hosszú egész "hálózati" sorrendben. v rövid egész VAX (little endian) sorrendben. V hosszú egész VAX (little endian) sorrendben. f szimpla pontosságú lebegőpontosságú szám natív formátumban. d dupla pontosságú lebegőpontos szám natív formátumban. p nulla lezárású füzérre mutató mutató. P struktúrára mutató mutató. u uuencode kódolású füzér. w BER kompresszált egész. A bájtok ebben a formában 128-as számrendszerben tartalmazzák a számot, a legnagyobb helyérték az első bájtban, a lehető legkevesebb bájton ábrázolva, és a legfelső bit minden bájtban nulla, kivéve az utolsó bájtot.
A Perl programozási nyelv – röviden
79/61
x Egy nulla bájt. X Egy bájt visszalépés. @ Nulla kitöltés abszolút pozícióig. Minden egyes betűt követhet egy szám, amely megadja, hányszor kell a betűt figyelembe venni. Minden típusnál, kivéve az ``a'', ``A'', ``b'', ``B'', ``h'', ``H'', és ``P'' típusokat a pack függvény ennyi argumentumot dolgoz fel az adott betűre a listából. A * mint ismétlési érték azt jelenti, hogy a lista maradék elemeit mind az adott típus szerint kell feldolgozni. Az ``a'' és ``A'' csak egy értéket vesz a listából, de a megadott szám hosszúságú füzért állít belőle elő nullákkal kiegészítve ha szükséges. Az unpack függvény használatakor az ``A'' leveszi a lezáró szóközöket és nullákat, de az ``a'' nem. Ennek megfelelően az ismétlési érték a ``b'' és ``B'' karaktereknél a bitek, a ``h'' és ``H'' karaktereknél a hexa digitek számát adja meg. A ``P'' esetén a szám a struktúra méretét adja meg, amelyre a mutató mutat. A valós számok (float és double) natív formában kerülnek tárolásra, mivel nincsen elfogadott szabvány, amely a hálózaton keresztüli adatcserét lehetővé tenné. Ez azt jelenti, hogy az egyik gépen összepakolt lebegőpontos számok nem feltétlenül kicsomagolhatók egy másikon, még akkor sem, ha mind a két gép IEEE lebegőpontos formátumot használ, mivel az IEEE formátum nem határozza meg a bájtsorrendet. A Perl nyelv belül, mint a C mindig duplapontosságú számokat használ, ezért a simapontosságúra való konverzió veszít a precizitásából. Emiatt például unpack(``f'', pack(``f'', $foo) == $foo nem feltétlenül igaz. $foo = pack("cccc",65,66,67,68); # foo eq "ABCD" $foo = pack("c4",65,66,67,68); # ugyanaz $foo = pack("ccxxcc",65,66,67,68); # foo eq "AB\0\0CD" $foo = pack("s2",1,2); # "\1\0\2\0" little-endian gépen # "\0\1\0\2" big-endian gépen $foo = pack("a4","abcd","x","y","z"); # "abcd" $foo = pack("aaaa","abcd","x","y","z"); # "axyz" $foo = pack("a14","abcdefg"); # "abcdefg\0\0\0\0\0\0\0" sub bintodec { unpack("N", pack("B32", substr("0" x 32 . shift, -32))); } Általánosan azt lehet mondani, hogy ugyanazt a TEMPLATE füzért lehet használni az unpack függvényben is. package NAMESPACE Egy fordítási egységet definiál az adott névterülethez. A package deklaráció hatásterülete az utasítást tartalmazó blokk végéig tart. Az utasítás után minden változó, amelyhez nincs explicit módon névterület megadva az adott névterülethez fog tartozni. Tipikusan ez az az utasítás, amely elsőkét szerepel egy olyan fájlban, amelyet egy require vagy use függvénnyel használ valamely Perl program. Egy ilyen csomagba több helyen is be lehet kapcsolódni, a package utasítás csak annyit mond a fordítónak, hogy mely névterületet használja a fordítás során a blokk végéig.
A Perl programozási nyelv – röviden
79/62
Más névterületen levő változókra, vagy fájlkezelőkre explicit névterület megadással lehet hivatkozni, a névterületet a változó neve elé kell írni két kettősponttal elválasztva: $csomag::változó. Ha a csomag neve nulla, akkor a main csomagot használja a Perl, azaz $::quty ugyanaz, mint $main::quty. pipe READHANDLE,WRITEHANDLE Egy csőpárt nyit meg, hasonlóan az ugyanilyennevű rendszerhíváshoz. Perl a csöveknél puffereket használ, ezért szükség lehet $| 1-re állítására a WRITEHANDLE kiürítésére minden egyes parancs után, az alkalmazás igényeinek megfelelően. pop ARRAY Kiveszi egy tömb utiolsó elemét, és visszatérési értékként adja. Ugyanaz a hatása, mint a $tmp = $ARRAY[$#ARRAY--]; utasításnak. Ha a tömbben nincsen egyetlen elem sem, akkor a visszatérési érték undef. Ha nincs argumentum megadva, akkor az @ARGV tömböt használja a főprogramban, és a @_ tömböt szubrutinokban, éppen úgy, mint a shift. pos SCALAR Azt a pozíciót adja meg, ahol a legutolsó m//g keresés megállt a SCALAR változóhoz. Érték is adható ennek a függvénynek, amelynek hatására a következő keresés annál a karakternél fog folytatódni, amelyet megadtunk. Példa # 11111 # 012345678901234 # | | | | $s = 'bbb abbbabb bbb'; while( $s =~ m/bb/g ){ print pos($s),"\n"; } amelynek kimenete 2 7 11 14 és # 111111 # 0123456789012345 # || || | || $s = 'bbb abbbabb bbb'; while( $s =~ m/bb/g ){ print $i=pos($s),"\n"; pos($s) = --$i; } amelynek kimenete 2 3 7 8 11
A Perl programozási nyelv – röviden
79/63
14 15 print FILEHANDLE LIST print LIST print A listában szereplő füzéreket nyomtatja ki. Visszatérési értéke TRU siker esetén. FILEHANDLE lehet egy skalár változó, amely esetben a változó által megadott füzért használja a Perl, mint a fájlkezelő nevét. Ha a FILEHANDLE nincs megadva, akkor a szabványos kimenetre nyomtat, illetve a legutoljára select függvénnyel kiválasztott csatornába. Ha a LIST lista is hiányzik, akkor $_ értékét írja ki. Mivel a print egy listát ír ki, ezért bármi, ami a print argumentumai között kiértékelődik lista környezetben értékelődik ki. Oda kell figyelni arra is, hogy ha a listában az első argumentum valamiért nyitózárójellel kezdődik, akkor ezt a Perl a print függvény argumentumait körülzáró nyitó zárójelnek veszi és a záró zárójel utáni listaelemeket nem nyomtatja ki. Vagy egy + jelet kell a nyitózárójel elé tenni, vagy az összes argumentumot még egy zárójelpárba kell zárni. Ha a FILEHANDLE neve egy tömb elemeként van megadva, vagy bármilyen más kifejezés értékeként, akkor a kifejezést kapcsos zárójelek közé kell tenni. print { $files[$i] } "stuff\n"; print { $OK ? STDOUT : STDERR } "stuff\n";
printf FILEHANDLE LIST printf LIST Ugyanaz, mint a print FILEHANDLE sprintf(LIST) utasítás. Az első argumentum adja meg a nyomtatási formátumot. prototype FUNCTION A függvény prototípusát adja meg, vagy undef értéket, ha a függvénynek nincsen prototípusa. push ARRAY,LIST Az ARRAY tömböt, mint egy vermet kezeli, és a LIST lista elemeit hozzáfűzi a tömb végéhez. Ennek megfelelően megnövekszik a tömb mérete. A visszatérési érték a tömb új mérete. Ugyanaz a hatása, mint a for $value (LIST) { $ARRAY[++$#ARRAY] = $value; }
utasításnak, csak sokkal hatékonyabb. q/STRING/ qq/STRING/ qx/STRING/ qw/STRING/ Általánosított idézőjel. Nem függvény, hanem operátor. quotemeta EXPRESSION
A Perl programozási nyelv – röviden
79/64
Az EXPRESSION kifejezés, mint füzér értékét adja vissza úgy, hogy minden reguláris kifejezés metakarakter \ karakterrel van megelőzve. Ez egy belső függvény, amely az idézőjelek között megadott füzérekben a \Q escape szekvenciát valósítja meg. rand EXPRESSION rand Egy véletlen valós számot ad vissza 0 és EXPRESSION között (EXPRESSION értéke pozitív kell, hogy legyen). Ha EXPRESSION nincs megadva, akkor 0 és 1 közötti értéket ad vissza. Ez a függvény minden futáskor ugyanazt a szekvenciát adja vissza, kivéve ha a srand függvényt is használjuk. Néhány Perl implementációban előfordulhat, hogy a rand függvény túl nagy, vagy túl kicsi értékeket ad vissza. Ennek oka, hogy a Perl értelmező fordításakor rosszul volt beállítva a RANDBITS C konstans. Ilyenkor az EXPRESSION kifejezést lehet az általában megfelelő kettő-hatvány értékkel megszorozni, de ezzel a program elveszti a hordozhatóságát. Sokkal jobb megoldás a megfelelő RANDBITS értékkel újrafordítani a programot. read FILEHANDLE,SCALAR,LENGTH,OFFSET read FILEHANDLE,SCALAR,LENGTH Megpróbál LENGTH bájtnyi adatot a SCALAR változóba olvasni a megadott FILEHANDLE fájlkezelőből. A visszatérési érték a valóban beolvasott bájtok száma vagy undef ha hiba történt. SCALAR mérete nőni vagy csökkenni fog annak megfelelően, hogy mennyi adatot olvas be a read. Ha OFFSET-et megadjuk, akkor ezzel meghatározhatjuk, hogy a SCALAR változóban hányadik bájttól kezdődően helyezze el a read függvény a beolvasott bájtokat. Ez a függvény a C stdio könyvtár fread függvényével lett megvalósítva. A valódi rendszerhíváshoz a sysread függvényt kell használni. readdir DIRHANDLE Megadja a következő könyvtári bejegyzést abból a könyvtárból, amelyet az opendir függvénnyel nyitottunk meg. Ha lista környezetben használjuk, akkor a maradék könyvtári bejegyzések listáját adja meg. Ha nincs több bejegyzés akkor undef értéket ad vissza skaláris környezetben, vagy nulla hosszúságú listát lista környezetben. Ha az így kapott értékeket, mint fájlneveket használod, akkor ne feledd el a megfelelő könyvtár nevet eléjük illeszteni, vagy egy chdir parancsot kiadni. opendir(DIR, $some_dir) || die "$some_dir nem nyitható meg: $!"; @dots = grep { /^\./ && -f "$some_dir/$_" } readdir(DIR); closedir DIR; readlink EXPRESSION Visszaadja a szimbolikus link értékét, ha a szimbolikus linkek a rendszeren implementálva vannak. Egyébként fatális hibát ad. Ha rendszerhiba történik a hívás során, akkor a visszatérési érték undef és $! tartalmazza a hibakódot. Ha EXPRESSION nincs megadva, akkor $_-t használja. recv SOCKET,SCALAR,LEN,FLAGS Fogad egy üzenetet a socket-en, Megpróbál LENGTH bájtnyi adatot fogadni a SCALAR változóba a SOCKET fájlkezelő által meghatározott socket-ből. A visszatérési érték a küldő címe. Hiba esetén a visszatérési érték undef. SCALAR mérete aszerint nő vagy csökken, hogy mennyi adatot kell tartalmaznia. FLAGS ugyanazokat az értékeket tartalmazhatja, mint a rendszerhívás. redo LABEL redo The Nem függvény, hanem Perl parancs, amely egy ciklust indít újra. Hatása hasonló a next utasításhoz, de nem értékeli ki ismételten a ciklus feltételt, hanem egyszerűen a ciklus elejére ugrik és a continue blokkot sem hajtja végre. Ha a LABEL nincs megadva, akkor az utasítást bezáró legbelső ciklusra vonatkozik. ref EXPRESSION Visszatérési értéke TRUE? ha EXPRESSION kifejezés egy referencia (mutató) és FALSE egyébként. Az érték, amelyet visszaad attól függ, hogy mi az az objektum amelyre a referencia vonatkozik. A beépített típusok: REF SCALAR
A Perl programozási nyelv – röviden
79/65
ARRAY HASH CODE GLOB Ha a hivatkozott objektum egy osztályhoz tartozik (lásd bless), akkor az osztály/csomag nevét adja meg. A ref egy kicsit olyan, mint a C-ben a typeof operátor. if (ref($r) eq "HASH") { print "r is a reference to an associative array.\n"; } if (!ref ($r) { print "r is not a reference at all.\n"; } rename OLDNAME,NEWNAME Átnevezi a fájlt OLDNAME névről NEWNAME névre. Visszatérési értéke 1 siker esetén és 0 egyébként. Nem működik fájlrendszerek között. require EXPRESSION require Megkövetel bizonyos szemantikát, amelyet az EXPRESSION kifejezés, vagy ennek hiányában $_ ad meg. Ha EXPRESSION numerikus, akkor azt követeli meg, hogy a futtató Perl verziója $] legalább ilyen vagy későbbi legyen. Egyéb esetben azt követeli meg, hogy egy könyvtári fájl betöltődjön, ha még nem lett betöltve. A fájl betöltése a do függvénnyel kerül betöltésre, amely az eval egy változata. A require szemantikája hasonlít a következő Perl-ben megírt függvényre: sub require { local($filename) = @_; return 1 if $INC{$filename}; local($realfilename,$result); ITER: { foreach $prefix (@INC) { $realfilename = "$prefix/$filename"; if (-f $realfilename) { $result = do $realfilename; last ITER; } } die "Can't find $filename in \@INC"; } die $@ if $@; die "$filename did not return true value" unless $result; $INC{$filename} = $realfilename; $result; } A fájl nem lesz kétszer betöltve azonos név alatt. A fájnak a kiértékelés során TRUE értéket kell visszaadnia, ez jelzi azt, hogy az inicializáló kód sikeresen futott le, ezért szokás ezeket a fájlokat egy lezáró '1;' utasítással befejezni. Ha EXPRESSION egy meztelen szó, akkor a require feltételezi, hogy a könyvtári fájl kiterjesztése .pm és a névben a :: jeleket kicseréli / jelekre. Ennél sokkal hatékonyabbés funkcionálisabb könyvtárbetöltési lehetőség a use használata. reset EXPRESSION reset
A Perl programozási nyelv – röviden
79/66
A ?? kereséseket, vagy változókat állít alaphelyzetbe (nullára). Ha nincsen megadva argumentum, akkor a ciklusban a mintaillesztési kereséseket állítja alaphelyzetbe, úgy, hogy azok a ciklus tesztben ismét megtalálják a megfelelő füzéreket. Ha argumentum van megadva, akkor az argumentum, mint karakterek listája kerül értelmezésre, és minden olyan változó, amelyiknek a neve ezen karakterek valamelyikével kezdődik lenullázódik. A mínuszjel karakter tartományok megadására megengedett. Csak az aktuális csomagban nullázza le a változókat illetve a kereséseket. return LIST Visszatér egy szubrutinból, vagy egy eval utasításból. Ha nem használjuk ezt az utasítást, akkor az eval utasítás, vagy a szubrutin a legutolsó végrehajtott utasítás értékével tér vissza. reverse LIST Lista környezetben a lista elemeit adja vissza fordított sorrendben. Skaláris környezetben a lista első elemének a bájtjait adja vissza fordított sorrendben. @q = (1,2,3,4); print reverse @q; print reverse 'alma'; $b = reverse 'alma'; print $b; és a kimenet (érdemes egy pillanatra elgondolkodni rajta) 4321almaamla rewinddir DIRHANDLE Visszaállítrja a könyvtárkezelőt a readdir utasításokhoz a könyvtár elejére. rindex STR,SUBSTR,POSITION rindex STR,SUBSTR Ugyanúgy működik, mint az index függvény, de nem az első, hanem a SUBSTR füzér utolsó STR-beli előfordulási helyét adja meg. Ha POSITION meg van adva, akkor az utolsó előfordulást, amely az előtt a pozíció előtt van, adja meg. rmdir FILENAME Törli a könyvtárat, amelyet a FILENAME ad meg, amennyiben az üres. Ha sikeres a törlés a visszatérési érték 1, egyébként 0 és a hibakód $!-ba kerül. Ha FILENAME nincs megadva, akkor $_ tartalmazza a fájl nevét. s/// Nem függvény, hanem a mintaillesztési és cserélési operátor. scalar EXPRESSION A kifejezést skaláris környezetben értékeli ki, és az így kapott értéket adja vissza. print reverse 'alma'; print scalar reverse 'alma'; Nincs ellentétes list operátor, mert általában nincsen rá szükség. Ha valamit lista környezetben kell kiértékelni, az vagy listakörnyezetben van úgyis, vagy használható a @{[ (kifejezés) ]} alak, amely esetén a kifejezés lista környezetben fog kiértékelődni. seek FILEHANDLE,POSITION,WHENCE Pozícionálja a FILEHANDLE fájlkezelőhöz rendelt fájlmutatót, éppen úgy, mint az fseek az stdio könyvtárban. FILEHANDLE lehet egy kifejezés, amelynek az értéke adja a fájlkezelő nevét. WHENCE értéke lehet 0 a fájlpozíció értéke POSITION lesz 1 a fájlpozíció értéke a mostani pozíció plusz POSITION 2 a fájlpozíció értéke POSITION a fájl végéhez viszonyítva. Használhatók a POSIX modulból a SEEK_SET, SEEK_CUR és SEEK_END szimbolikus konstansok. Visszatérési értéke 1 siker esetén, és nulla hiba esetén. Néhány rendszer megköveteli a seek meghívását egy fájlon belüli olvasási és írási műveletek között. Ilyenkor a seek(TEST,0,1);
A Perl programozási nyelv – röviden
79/67
utasítás használható a fájlmutató helyben hagyásához. Ez arra is jó, hogy ha fájl végére értünk, és egy másik processz írja a fájlt, akkor törli a fájlvége feltételt. Ellenkező esetben a Perl egy újabb műveletnél nem próbál meg olvasni a fájlból, akkor sem ha közben valaki írt bele. Ellenben ha a seek függvényt meghívjuk, akkor újra próbálkozik. Ha ez mégsem működne (végül is a Perl rendszer C-ben van megírva, és minden rendszeren a stdio könyvtárat használja, és ez a működés ettől függ) akkor valami ehhez hasonlót kell megpróbálni: for (;;) { for ($curpos = tell(FILE); $_ = ; $curpos = tell(FILE)) { # itt csinálunk valamit és kiírunk a fájlba } sleep($for_a_while); seek(FILE, $curpos, 0); } seekdir DIRHANDLE,POS Beállítja a readdir számára a könyvtárpozíciót a DIRHANDLE könyvtárkezelőhöz. A POS pozíció egy olyan érték kell, hogy legyen, amelyet a telldir adott vissza értékként. select FILEHANDLE select A pillanatnyilag kiválasztott fájlkezelőt adja vissza értékként, illetve beállítja a az alapértelmezett fájlkezelőt a kiment számára, amennyiben FILEHANDLE argumentumkéntmeg van adva. Ennek két hatása van: Egy write vagy print függvény ezt a fájlkezelőt fogja használni, ha más fájlkezelő nincs megadva. Azok a változók, amelyek a kimeneti fájlra vonatkoznak erre a fájlra fognak vonatkozni, például a $^ vagy $| változók. A FILEHANDLE lehet egy olyan kifejezés, amelynek értéke, mint füzér adja meg a fájlkezelő nevét. Így a tipikus használat például a pufferelés kikapcsolására: $oldfh = select(STDERR); $| = 1; select($oldfh); select RBITS,WBITS,EBITS,TIMEOUT Ez a hívás a select(2) rendszerfüggvényt hívja meg a megfelelő bitmaszkkal, amelyet a fileno és vec függvényekkel lehet előállítani a következőképpen: $rin = $win = $ein = ''; vec($rin,fileno(STDIN),1) = 1; vec($win,fileno(STDOUT),1) = 1; $ein = $rin | $win; Ha sok fájlkezelőt egyszerre akarsz kiválasztani, akkor a következő szubrutin segíthet: sub fhbits { local(@fhlist) = split(' ',$_[0]); local($bits); for (@fhlist) { vec($bits,fileno($_),1) = 1; } $bits; } $rin = fhbits('STDIN TTY SOCK');
A Perl programozási nyelv – röviden
79/68
A szokásos forma: ($nfound,$timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout); vagy blokkolni, amíg valami rendelkezésre nem áll $nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef); A legtöbb rendszer nem ad vissza semmit a $timeleft-ben, ezért a select hívása skaláris környezetben csak $nfound értéket ad vissza. A bitmaszkok bármelyike lehet undef. Az időhatár (timeout) ha meg van adva, akkor másodpercben értendő, de lehet tört érték is. Nem minden implementáció képes a $timeleft kiszámítására. Ebben az esetben ezek a rendszerek a $timeleft változóban a megadott értéket adják vissza. Egy 250 milli-másodperces várakozást a következőképpen lehet megvalósítani: select(undef, undef, undef, 0.25); FIGYELMEZTETÉS: Ne keverd a pufferelt i/o műveleteket a select függvény használatával. Ilyenkor a sysread függvényt kell használni. semctl ID,SEMNUM,CMD,ARG Meghívja a System V IPC semctl függvényt. Ha CMD &IPC_STAT vagy &GETALL akkor ARG egy változó kell, hogy legyen, amely a visszaadott semid_ds struktúrát fogja tartalmazni vagy a szemafor tömböt. A visszatérési érték olyan, mint ioctl esetében, undef hiba esetén, ``0 de TRUE''zero esetén, illetve a visszatérési érték egyébként. semget KEY,NSEMS,FLAGS Meghívja a System V IPC semget függvényt. Visszaadja a szemafort, vagy undef értéket hiba esetén. semop KEY,OPSTRING Meghívja a System V IPC semop függvényt a szemafor műveletekhez, mint jelzés és várakozás. OPSTRING egy csomagolt tömb kell, hogy legyen, amely semop struktúrákat tartalmaz. Minden egyes semop struktúra előállítható a pack(``sss'',$semnum, $semop, $semflag) függvénnyel. A szemafor operációk számát az OPSTRING hossza adja meg. Visszatérési értéke TRUE siker esetén, és FALSE ha hiba történt. send SOCKET,MSG,FLAGS,TO send SOCKET,MSG,FLAGS Üzenetet küld egy socket-re. Ugyanazt a flag-et használja, mint a rendszerhívás. Kapcsolat nélküli socket esetében meg kell határozni a cél TO címet is. Ebben az esetben a C sendto() függvénynek megfelelő a működés. Az elküldött karakterek számát adja meg, vagy undef értéket, ha valamilyen hiba történt. setpgrp PID,PGRP Beállítja a processz csoportot a megadott PID-hez, illetve az aktuális processzhez, ha a PID nulla. Fatális hibát generál olyan rendszereken, amelyeken nincs implementálva. Ha az argumentumok nincsenek megadva, akkor az alapértelmezés 0,0. Mivel POSIX-ban a setgrp nem fogad el argumentumokat, ezért csak a setgrp 0,0 a hordozható kód. setpriority WHICH,WHO,PRIORITY Beállítja az aktuális prioritást egy processzhez, csoporthoz, vagy felhasználóhoz. Fatális hibát generál olyan rendszereken, amelyeken nincs implementálva. setsockopt SOCKET,LEVEL,OPTNAME,OPTVAL
A Perl programozási nyelv – röviden
79/69
Beállítja a kért socket opciót. Visszatérési értéke undef hiba esetén. OPTVAL megadható undef-ként ha nem akarunk argumentumot megadni. shift ARRAY shift Kiveszi egy tömb első elemét és visszaadja visszatérési értékként. A tömb eggyel rövidebb lesz, minden egyes elemet eggyel lejjebb húzva a tömbbe. Ha a tömbben nincsenek elemek, akkor undef értéket ad vissza. Ha nincs argumentum megadva, akkor az @ARGV tömböt használja a főprogramban, és a @_ tömböt szubrutinokban, éppen úgy, mint a pop. Ellentéte az unshift. Hasonló függvények a pop illetve ennek a párja a push. shmctl ID,CMD,ARG Meghívja a System V IPC shmctl rendszerhívást. Ha a CMD &IPC_STAT, akkor ARG egy olyan változó kell, hogy legyen, amely a visszaadott shmid_ds struktúrát fogja tartalmazni. A visszatérési értéke olyan, mint az ioctl függvénynek: undef hiba esetén, "0 de TRUE" zero visszatérési érték esetén, és a rendszerfüggvény által visszaadott érték egyébként. shmget KEY,SIZE,FLAGS Meghívja a System V IPC shmget rendszerfüggvényt. A visszatérési érték a megosztott memória szegmens azonosító, illetve undef egyébként. shmread ID,VAR,POS,SIZE shmwrite ID,STRING,POS,SIZE Olvas vagy ír a System V ID azonosítójú megosztott memória szegmensből illetve abba, a POS pozíciótól kezdődően SIZE hosszan hozzáfűzve, be-, kimásolva, illetve leválasztva. Olvasáskor VAR egy változó, amely a kiolvasott értéket fogja tartalmazni. Íráskor, ha a STRING füzér túl hosszú, csak az első SIZE bájtot fogja kiírni a rendszer. Visszatérési érték TRUE siker esetén FALSE hiba esetén. shutdown SOCKET,HOW Lelő egy socket kapcsolatot. A HOW paraméter adja meg a lelövés módját, éppen úgy, ahogy az azonos nevű rendszerhívásnál. sin EXPRESSION Az EXPRESSION kifejezés szinuszát adja vissza. Az argumentumot radiánban értelmezi. Ha nincs megadva argumentum, akkor $_ szinuszát adja vissza. sleep EXPRESSION sleep A függvény hatására a program EXPRESSION másodpercre megáll, alszik, illetve meghatározatlan időre alszik, ha nincs megadva argumentum. Ebből az állapotból az idő lejártával, vagy egy SIGALRM szignállal lehet kihozni a programot. A visszatérési érték a valóban alvással eltöltött másodpercek száma. Általában nem lehet az alarm és sleep függvényeket vegyesen használni, mert a legtöbb rendszeren a sleep függvény az alarm függvény felhasználásával van implementálva. Néhány öregebb rendszeren egy másodperccel kevesebbet alszik a program, mint a valóban megkívánt. Ennél finomabban beállítható várakozásra a Perl syscall függvényét lehet használni a setitimer(2) felület eléréséhez, ha ez az adott rendszeren elérhető, vagy a select függvényt. socket SOCKET,DOMAIN,TYPE,PROTOCOL Megnyitja a megfelelő típusú socket-et és hozzárendeli a SOCKET fájlkezelőhöz. DOMAIN, TYPE és PROTOCOL ugyanazt jelentik, mint a rendszerhívás esetében. Feltehetőleg használni kell a use Socket parancsot a megfelelő definíciók betöltéséhez. socketpair SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL Létrehoz egy pár, név nélküli socket-et a definiált tartományban. DOMAIN, TYPE és PROTOCOL ugyanazt jelentik, mint a rendszerhívás esetében. Ha nincs implementálva fatális hibát ad. Visszatérési értéke TRUE siker esetén. sort SUBNAME LIST
A Perl programozási nyelv – röviden
79/70
sort BLOCK LIST sort LIST A LIST listát adja vissza rendezve. A tömb nem létező elemeit törli. Ha SUBNAME vagy BLOCK hiányzik, akkor a szabványos füzérsorrendbe rendez. Ha SUBNAME meg van adva, akkor ez annak a szubrutinnak a neve, amely az elemi összehasonlítások eredményeképpen negatív, nulla vagy pozitív számot ad attól függően, hogy hogyan kell rendezni a tömböt. (A <=> operátor rendkívül fontos ezekben a szubrutinokban.) SUBNAME lehet egy skaláris változó, amely esetben a változó értéke adja meg a hasonlításokhoz használt szubrutin nevét. A SUBNAME helyén megadható egy BLOCK blokk, mint egy rövid, egyszerű szubrutin. A hatékonyság kedvéért a szokásos szubrutinhívási eljárásokat kihagyja a rendszer, aminek a következő következményei vannak: a szubrutin nem lehet rekurzív, a két hasonlítandó elem nem a szokásos @_ tömbben kerül átadásra, hanem a csomagszinten globális $a és $b változókban. Példák: # lexikális rendezés @articles = sort @files; # ugyanaz, csak most expliciten meg van adva a hasonlító blokk @articles = sort {$a cmp $b} @files; # kisbetű/nagybetű most nem számít @articles = sort { uc($a) cmp uc($b)} @files; # és ugyanez fordított sorrendben @articles = sort {$b cmp $a} @files; # numerikusan növekvő sorrendbe @articles = sort {$a <=> $b} @files; # numerikusan csökkenő sorrendbe @articles = sort {$b <=> $a} @files; # expliciten megadott szubrutin névvel sub byage { $age{$a} <=> $age{$b}; # presuming integers } @sortedclass = sort byage @class; # az %age tördelőtábla kulcsai az értékek szerint # rendezve @eldest = sort { $age{$b} <=> $age{$a} } keys %age; sub backwards { $b cmp $a; } @harry = ('dog','cat','x','Cain','Abel'); @george = ('gone','chased','yz','Punished','Axed'); print sort @harry; # prints AbelCaincatdogx print sort backwards @harry; # prints xdogcatCainAbel print sort @george, 'to', @harry; # prints AbelAxedCainPunishedcatchaseddoggonetoxyz splice ARRAY,OFFSET,LENGTH,LIST splice ARRAY,OFFSET,LENGTH splice ARRAY,OFFSET
A Perl programozási nyelv – röviden
79/71
Kiveszi az OFFSET és LENGTH paraméterek által meghatározott részét az ARRAY tömbnek, és helyette berakja a LIST lista elemeit, ha meg van adva lista. Visszatérési értéke a kivett elemek listája. A tömb csökken, vagy nő, ahogy szükséges. Ha LENGTH nincs megadva, akkor az OFFSET értéktől kezdődően mindent kivesz. A következő utasítások azonosak, (feltételezzük, hogy $[ értéke nulla): push(@a,$x,$y) splice(@a,$#a+1,0,$x,$y) pop(@a) splice(@a,-1) shift(@a) splice(@a,0,1) unshift(@a,$x,$y) splice(@a,0,0,$x,$y) $a[$x] = $y splice(@a,$x,1,$y); split /PATTERN/,EXPRESSION,LIMIT split /PATTERN/,EXPRESSION split /PATTERN/ split Feldarabol egy füzért füzérek tömbjére, és a listát adja vissza. Ha nem listakörnyezetben szerepel, akkor a megtalált mezők számát adja vissza, amelyek belekerültek a @_ tömbbe. (Listakörnyezetben is rá lehet venni a split függvényt, hogy a @_ tömbbe helyezze el az elemeket azzal, hogy ?? jeleket használunk, mint reguláris kifejezés határolókat, de ekkor is a listaelemeket adja vissza a függvény. Ugyanakkor az implicit módon @_-ba történő vágás ellenjavallt. Ha nincsen megadva EXPRESSION kifejezés, akkor $_ értékét darabolja fel a függvény. Ha a PATTERN reguláris kifejezés sincsen megadva, akkor a szóközök mentén vágja szét a füzért a függvény (a bevezető szóközök után). Ha LIMIT meg van adva és pozitív, akkor legfeljebb ennyi mezőre vágja szét a füzért. Ha LIMIT nincs megadva, akkor a keletkező lista végén lévő üres mezőket levágja a függvény. Ha a LIMIT negatív, akkor azt úgy kezeli a függvény, mintha tetszőlegesen nagy lenne a LIMIT. Ha a PATTERN megfelel a null füzérnek, akkor a füzért minden egyes karakter között elvágja, így például print join(':', split(/ */, 'hi there')); kimenete h:i:t:h:e:r:e A LIMIT megadásával részlegesen lehet felvágni füzéreket. ($login, $passwd, $remainder) = split(/:/, $_, 3); Amikor egy listának adunk értéket a függvénnyel, akkor a Perl automatikusan a lista elemeinek száma plusz egy értéket ad meg LIMIT-ként, ezzel is csökkentve a felesleges műveleteket. Az előbbi példában LIMIT értéke alapértelmezés szerint négy lett volna. Ha a PATTERN reguláris kifejezésen belül zárójeleket használunk, akkor minden egyes részfüzérre, amely megfelel a bezárójelezett résznek egy újabb listaelem keletkezik, például: print join(':',split(/([,-])/, "1-10,20", 3)); kimenete 1:-:10:,:20 A reguláris kifejezés PATTERN helyettesíthető egy változóval, amelyiknek az értéke tartalmazza a reguláris kifejezést.
A Perl programozási nyelv – röviden
79/72
sprintf FORMAT,LIST A visszatérési értéke egy formázott füzér a C-ben megszokott printf formátumoknak megfelelően. Az indirekt hosszat jelőlő * karakter nem támogatott, de Perl-ben ezt sokkal egyszerűbben meg lehet oldani, csak be kell írni a változót az idézőjelek (és nem aposztrófok) közé zárt füzérbe. sqrt EXPRESSION Az EXPRESSION kifejezés négyzetgyökét adja vissza. Ha nincs megadva argumentum, akkor $_ négyzetgyökét számítja ki. srand EXPRESSION Véletlenszám kezdeti értéket ad meg a rand függvény számára. Ha az EXPRESSION kifejezés nincs megadva, akkor a pillanatnyi időből, a processz azonosítóból és egyéb dolgokból állít elő egy kezdőértéket. Titkosításhoz nem ajánlott a használata. stat FILEHANDLE stat EXPRESSION Egy 13 elemű tömböt ad vissza, amely a fájl státuszát adja meg. A fájl vagy meg van nyitva és a FILEHANDLE fájlkezelőhöz rendelve, vagy EXPRESSION adja meg a nevét. Hiba esetén nulla listát ad vissza. Tipikus felhasználás: ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename); Nem minden mező támogatott minden fájlrendszerben. Az egyes mezők értelme: dev az eszköz száma ino inode száma mode fájlmód, típus és engedélyek nlink a hard linkeke száma a fájlhoz uid a fájl tulajdonosának numerikus azonosítója gid a fájlt tulajdonosának numerikus csoport azonosítója rdev eszközazonosító (speciális fájloknál) size a fájl teljes mérete bájtokban atime a fájl utolsó hozzáférési időpontja mtime a fájl utolsó módosítási időpontja ctime az indode változásának ideje blksize preferált blokk méret blocks a pillanatnyilag lefoglalt blokkok száma (Az időpontok 1970. január 1 0:00 GMT óta eltelt másodpercekben vannak megadva, mint általában minden időpont a UNIX-os rendszerekben.) Ha a stat-nak egy speciális fájlnevet, az aláhúzás karaktert adjuk meg akkor nem hívja meg a rendszerfüggvényt, hanem a legutolsó fájltesztelés, vagy stat eredményeit használja. study SCALAR study Megvizsgálja a megadott SCALAR füzért, illetve $_ tartalmát, hogy az ezután következő mintaillesztéseket gyorsabban, a vizsgálat eredményének megfelelően optimalizálva hajthassa végre. Ez vagy megspórol valamennyi időt, vagy nem, mindig a konkrét esettől függően. Általában meg lehet próbálni a futást study-val és anélkül. Azok a ciklusok, amelyek sok apró konstans füzérre keresnek rá, gyorsulnak fel a leginkább. Egy időben csak egy ilyen vizsgálat lehet aktív. Egy második skalár megvizsgálásának hatására az elsőt elfelejti a rendszer. sub BLOCK sub NAME
A Perl programozási nyelv – röviden
79/73
sub NAME BLOCK Ez nem egy beépített függvény, hanem szubrutin definíció. Csak névvel, és feltehetőleg prototípussal megadva csak egy deklaráció. Név nélkül egy olyan kifejezés, amely egy referenciát ad vissza a definiált kódszegmenshez, és névvel, és blokkal együtt szabályos szubrutin definíció. substr EXPRESSION,OFFSET,LEN substr EXPRESSION,OFFSET Kiveszi az EXPRESSION kifejezésből a részfüzért és visszaadja értékként. Az első karakter indexe 0 vagy amilyen értékre $[ lett állítva. Ha az OFFET értéke negatív, akkor ennyi karakterre a füzér végétől kezdi a részfüzért. Ha LEN nincs megadva, akkor az OFFSET értékének megfelelő karaktertől a füzér végéig veszi a karaktereket. Ha LEN értéke negatív, akkor ennyi karaktert hagy meg a füzér végén. A substr függvény használható balértékként, azaz ilyen fügvvénnyel alkotott részfüzérnek értéket lehet adni, de ebben az esetben EXPRESSION is balérték kell, hogy legyen. Ha az értékadás során a LEN értékénél kevesebb karaktert teszünk az alfüzér helyére, akkor az eredményül kapott füzér rövidebb lesz, ha többet, akkor hosszabb lesz. Példák: $k = "Almás deres\n"; print substr($k,2,4); print substr($k,-6); print substr($k,6,-1); print substr($k,-7,-2); substr($k,0,5) = "\nRétes"; print $k; és a kimenet: más deres deres dere Rétes deres symlink OLDFILE,NEWFILE Létrehoz egy szimbolikus linket NEWFILE néven, amely az OLDFILE fájlhoz lesz kapcsolva. Visszatérési értéke 1 siker esetén, és 0 egyébként. Azokon a rendszereken, amelyek a szimbolikus linkeket nem támogatják fatális hibát okoz. syscall LIST Meghívja a rendszerhívást, amelyet a LIST lista első eleme meghatároz. Ha nincs implementálva fatális hibát okoz. Az egyes argumentumok a következőképpen kerülnek felhasználásra: numerikus argumentum esetén int értéket ad át a program a rendszerhívásnak. füzér argumentum esetén a füzérre mutató mutatót adja át értékként a rendszer. Ekkor a hívó feladata, hogy a füzér megfelelően hosszú legyen a visszaadott érték fogadására. A numerikus argumentumok esetén az egyes argumentumokhoz hozzá lehet adni nullát, hogy biztosan numerikusnak tekintse a Perl. require 'syscall.ph'; syscall(&SYS_write, fileno(STDOUT), "ki van ott?\n", 9);
A Perl maximum 14 argumentumot ad át a rendszernek, ami a gyakorlatban elegendő kell, hogy legyen. sysopen FILEHANDLE,FILENAME,MODE sysopen FILEHANDLE,FILENAME,MODE,PERMS
A Perl programozási nyelv – röviden
79/74
A FILENAME névvel megadott fájlt nyitja meg és hozzárendeli a FILEHANDLE fájlkezelőhöz. Ha FILEHANDLE egy kifejezés, akkor ennek értéke adja meg a fájlkezelő nevét. Ez a függvény az operációs rendszer open függvényét hívja meg a FILENAME, MODE, PERMS paraméterekkel. A lehetséges bit értékek a MODE paraméter számára rendszerfüggők, és a szabványos Fcntl modulon keresztül érhetők el. Ugyanakkor hagyomány okok miatt néhány érték univerzális, így nulla csak olvasásra, egy csak írásra és kettő írásra, olvasásra nyitja meg a fájlt. Ha a fájl nem létezik, akkor a rendszerhívás létrehozza (általában azért, mert a MODE tartalmazza az O_CREAT bitet), majd ezután a PERM engedélyezési értéket rendeli hozzá. Ha PERM hiányzik, akkor alapértelmezés szerint 0666 az értéke (vigyázat, ez oktális szám, nem sátánista jelkép) amely alapján mindenki olvashatja és írhatja a fájlt. sysread FILEHANDLE,SCALAR,LENGTH,OFFSET sysread FILEHANDLE,SCALAR,LENGTH Megpróbál LENGTH bájtnyi adatot olvasni a SCALAR változóba a FILEHANDLE fájlkezelőhöz rendelt fájlból a rendszer read(2) parancsát használva. Ez a függvéyn kikerüli az stdio könyvtárat, így más olvasási műveletekkel együtt használva zavarodástokozhat. A beolvasott bájtok számát adja vissza értékként, vagy undef értéket, ha hiba történt. SCALAR mérete csökkenni, vagy növekedni fog attól függően, hogy hány bájtot olvasott be a rendszer. Megadható egy OFFSET érték, amely azt határozza meg, hogy a beolvasott bájtokat a SCALAR változóba hol kell elhelyezni. system LIST Ugyanazt teszi, mint az exec, kivéve, hogy egy fork hajtódik először végre, és az apa processz vár a gyerek processzre. Az argumentumkezelés függ az argumentumok számától. A visszaadott érték az a kilépési státusz érték, amelyet a wait függvény ad vissza. A valódi processz kilépési érték ennek 256-od része. syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET syswrite FILEHANDLE,SCALAR,LENGTH LENGTH bájtot ír a SCALAR változóból a FILEHANDLE fájlkezelőhöz rendelt fájlba a write(2) rendszerhívás segítségével. Kihagyja a szabványos stdio könyvtárat, ezért más kiírási műveletekkel való keverése igen érdekes, és nem kívánt eredményeket adhat. A kiírt bájtok számát adja vissza vagy undef értéket ha hiba történt. Az OFFSET értékével lehet megadni, hogy hol kezdődik az a bájtsor amit ki kell írni, ha nem a SCALAR változó első bájtjától kezdve akarunk írni. tell FILEHANDLE tell Visszaadja az aktuális fájlpozíciót a FILEHANDLE fájlkezelőhöz. A FILEHANDLE fájlkezelő lehet egy kifejezés, ilyenkor a kifejezés értéke adja meg a használandó fájlkezelő nevét. Ha FILEHANDLE nincs megadva, akkor a legutoljára használt fájlkezelőt használja. telldir DIRHANDLE Visszaadja a DIRHANDLE könyvtárkezelő aktuális pozícióját, amelyet a readdir függvény használ. A visszaadott érték adható át a seekdir függvénynek. tie VARIABLE,CLASSNAME,LIST Ez a függvény egy változót köt egy osztályhoz (csomaghoz), amely osztály tartalmazza a változóval végezhető műveleteket. VARIABLE a változó neve. CLASSNAME az osztály neve, amely implementálja a műveleteket. Minden további argumentumot az osztályon belüli new metódusnak ad át a rendszer. Ezek olyan argumentumok, amelyeket a C programozási nyelv dbm_open() függvényének lehet például átadni. Az objektum, amelyet a tie függvény visszaad a new metódus által létrehozott, és visszaadott objektum. Megjegyzendő, hogy az olyan függvények, mint a keys vagy values igen nagy tömböket eredményezhetnek olyan tördelőtáblák esetén, amelyek nem memóriában vannak tárolva, hanem a tie függvénnyel DBM fájlokhoz vannak rendelve. Ilyen esetben sokkal inkább az each függvényt kell használni, amely egyenként veszi elő az egyes elemeket. use NDBM_File; tie(%HIST, 'NDBM_File', '/usr/lib/news/history', 1, 0);
A Perl programozási nyelv – röviden
79/75
while (($key,$val) = each %HIST) { print $key, ' = ', unpack('L',$val), "\n"; } untie(%HIST); Az osztály, amely egy tördelőtáblát hoz létre a következő metódusokat kell, hogy megvalósítsa: TIEHASH CLASSNAME, LIST DESTROY this FETCH this, key STORE this, key, value DELETE this, key EXISTS this, key FIRSTKEY this NEXTKEY this, lastkey Az osztály, amely közönséges tömböt valósít meg a következő metódusokat kell, hogy megvalósítsa: TIEARRAY CLASSNAME, LIST DESTROY this FETCH this, key STORE this, key, value Az osztály, amely skalárt valósít meg a következő metódusokat kell, hogy megvalósítsa: TIESCALAR CLASSNAME, LIST DESTROY this FETCH this, STORE this, value Ellentétben a dbmopen függvénnyel a tie függvény nem olvas be semmilyen modult, ezt a programnak egy külön require vagy use függvénnyel kell megtennie, ha szükséges. tied VARIABLE Ahhoz az objektumhoz ad egy referenciát, amelyet a tie függvény adott vissza, amikor a változót egy osztályhoz kötötte. Ha a változó nem lett semmilyen osztályhoz kötve, akkor undef értéket ad vissza. time A másodpercek számát adja meg, amely a kezdetek óta eltelt. (Ez 1904 január 1. 00:00:00, a MacOS operációs rendszeren, más rendszereken 1970 január 1. 00:00:00 gmt) Ez az érték adható át argumentumként a gmtime vagy localtime függvényeknek. times Egy négyelemű tömböt ad vissza, amely a processz és a gyermek processzek által elfogyasztott felhasználói és rendszer időt adja meg. ($user,$system,$cuser,$csystem) = times; tr/// A transzlációs operátor. truncate FILEHANDLE,LENGTH truncate EXPRESSION,LENGTH Levágja a fájl végét, amelynek a nevét az EXPRESSION kifejezés adja meg, vagy a FILEHANDLE fájlkezelőhöz van rendelve. Fatális hibát ad olyan rendszeren ahol nincs implementálva. uc EXPRESSION A nagybetűs változatát adja vissza az EXPRESSION kifejezésnek. Ez a belső függvény, amely megvalósítja az idézőjelek közötti \U escape szekvenciát. Minden POSIX setlocale() beállítást figyelembe kell vennie. ucfirst EXPRESSION
A Perl programozási nyelv – röviden
79/76
Az EXPRESSION kifejezést adja vissza, az első betűt nagybetűre konvertálva. Ez a belső függvény, amely megvalósítja az idézőjelek közötti \u escape szekvenciát. Minden POSIX setlocale() beállítást figyelembe kell vennie. umask EXPRESSION umask Beállítja a processz számára az umask értékét, és a régit adja vissza. Ha EXPRESSION nincs megadva, akkor nem állít semmit, csak az aktuális umask értéket adja vissza. undef EXPRESSION undef Az EXPRESSION kifejezés által megadott balértéket teszi nem definiálttá. Skalárra, tömbre és szubrutinra alkalmazható. Mindig nem definiált értéket ad vissza. Ha az EXPRESSION kifejezés hiányzik, akkor semmi más hatása nincs, mint a nem definiált értéket adja vissza, amelyet például fel lehet használni, mint szubrutin visszatérési értéket. undef $foo; undef $bar{'blurfl'}; undef @ary; undef %assoc; undef &mysub; return (wantarray ? () : undef) if $they_blew_it; unlink LIST Törli a LIST listában megadott fájlokat. A sikeresen törölt fájlok számát adja meg. Megjegyzés: az unlink nem töröl könyvtárakat, csak akkor ha superuser módban fut a processz, és a Perl a -U kapcsolóval lett elindítva. Azonban még ebben az esetben is gondokat okozhat a fájlrendszerben egy könyvtár fájlként való eltávolítása. Sokkal biztonságosabb módszer az rmdir használata. unpack TEMPLATE,EXPRESSION Az unpack a pack ellentéte: az EXPRESSION kifejezésben megadott füzért a TEMPLATE-nek megfelelően bontja fel értékekre, és ezek listáját adja vissza. Skalár környezetben az első értéket adja vissza. A TEMPLATE formátuma ugyanaz, mint a pack függvénynél. A következő példaprogram a substr és ord függvényeket valósítja meg: sub substr { local($what,$where,$howmuch) = @_; unpack("x$where a$howmuch", $what); } sub ord { unpack("c",$_[0]); } Ezen túlmenően minden mezőjelölő karaktert megelőzhet egy %<xxx> jelölés, amely esetben nem a mező értékét adja meg az unpack hanem annak xxx bites ellenőrző összegét. A következő példa a System V sum parancsát valósítja meg: while (<>) { $checksum += unpack("%16C*", $_); } $checksum %= 65536; A következő példa hatékonyan számolja össze egy bitvektor bitjeit: $setbits = unpack("%32b*", $selectmask); untie VARIABLE Megszünteti a hozzárendelést egy változó és egy osztály között, amelyet a tie hozott létre. unshift ARRAY,LIST
A Perl programozási nyelv – röviden
79/77
A shift függvény ellentéte. A LIST listát fűzi az ARRAY tömb elejére és az így kapott új tömb elemeinek a számát adja vissza. A LIST lista egésze, egyszerre lesz a tömb elejére illesztve, így a sorrend a tömb elején ugyan az lesz, mint a listában. Ha nem ez a kívánatos, akkor a reverse függvénnyel lehet a LIST lista elemeinek sorrendjét megfordítani. use Module LIST use Module use Module VERSION LIST use VERSION Beimportál egy modult, és általában, a modultól függően néhány szubrutin nevet az importáló modulban elhelyez. A hatása ugyanaz, mint a BEGIN { require Module; import Module LIST; } utasításnak, kivéve, hogy a Module a use esetében fix szó kell, hogy legyen, nem lehet füzér kifejezés. Ha az első argumentum nem modul név, hanem szám, akkor a Perl megvizsgálja, hogy a saját verziója eléri-e ezt az értéket, és ha nem, akkor egy hibajelzés után azonnal leáll. Ezzel lehet megkövetelni azt a Perl verziót, amely alatt a program hibásan hajtódna végre. A use estében a modul beimportálása fordítási időben történik, ezt a fenti ekvivalens példában a BEGIN éri el. Az import nem egyéb, mint egy, a modulban definiált statikus szubrutin, amely általában neveket rak át az importáló csomag névterületére. A modul olyan módon implementálhatja saját import szubrutinját, ahogy csak akarja, de a legtöbb csomag csak egyszerűen örökli az Exporter csomagból. Ha az importáló nem akarja, hogy a névterülete megváltozzon, akkor a use Module (); alakot kell használni, amely ekvivalens a BEGIN { require Module; } formával. Ha a VERSION szerepel a Modul és a LIST lista között, akkor a use hibát okoz, ha a csomagban a $VERSION változó értéke kisebb, mint VERSION. Mivel ez a formátum megfelelően nyitott, ezért sok fordítási direktíva is ebben a formában van megvalósítva. A pillanatnyilag implementált direktívák: use integer; use diagnostics; use sigtrap qw(SEGV BUS); use strict qw(subs vars refs); use subs qw(afunc blurfl); Ezek a pszeudo modulok a pillanatnyi blokk környezetben fejtik ki a hatásukat ellentétben az igazi modulokkal, amelyek a névtartományt módosítják, és így a fájl végéig hatásosak. Van egy no parancs, amely a use ellentéte, és amely ennek megfelelően nem az import, hanem az unimport szubrutint hívja meg.
A Perl programozási nyelv – röviden
79/78
utime LIST Megváltoztatja a hozzáférési és a módosítási idejét a LIST listában szereplő fájloknak. A lista első két argumentuma a numerikus időérték a hozzáférési és módosítási időre. Visszatérési értéke a sikeresen módosított fájlok száma. Ugyanakkor az inode módosítási idő az aktuális idő lesz. Példaképp a touch program egy egyszerű megvalósítása: #!/usr/bin/perl $now = time; utime $now, $now, @ARGV; values ASSOC_ARRAY A visszatérési értéke egy tömb, amely a tördelőtábla értékeit tartalmazza. Skaláris környezetben az elemek számát adja vissza. A visszaadott tömbben az értékek sorrendje nem meghatározott, de definiáltan ugyan az, mint a kulcsokra a keys függvény által visszaadott tömbbeli sorrend, vagy az each függvény által biztosított sorrend. vec EXPRESSION,OFFSET,BITS Az EXPRESSION kifejezést, mint olyan bitsort értelmezi, amelyben BITS darabnyi bitet tartalmazó csomagok vannak egymás után, és az OFFSET értéke által megadott csomagot adja értékként. Ha a vec függvényt, mint balértéket kezeljük, akkor természetesen az EXPRESSION kifejezésnek is balértéknek kell lennie, és használni kell a zárójeleket a megfelelő végrehajtási sorrend eléréséhez. Az így kezelt vektorokkal a logikai bitenkénti |, & és ^ használhatók. #!/usr/bin/perl vec($v,3,8)=64; print unpack("b*", $v),"\n"; vec($v,9,1)=1; vec($v,11,1)=1; print unpack("b*", $v),"\n"; vec($v,0,3)=255; print unpack("b*", $v),"\n"; és a kimenet 00000000000000000000000000000010 00000000010100000000000000000010 11100000010100000000000000000010 wait Vár egy gyermekprocessz leállására, és a leálló processz azonosítóját adja vissza, illetve -1 értéket, ha nincs futó gyermekprocessz. A leálló processz státusza a $? változóba kerül. waitpid PID,FLAGS Egy azonosítójával adott gyermekprocessz lefutására vár, és a leálló processz azonosítóját adja vissza, illetve -1 értéket, ha nincs ilyen azonosítójú futó gyermekprocessz. A leálló processz státusza a $? változóba kerül. wantarray A visszatérési értéke TRUE, ha az aktuális szubrutinhívás listakörnyezetből történik. Tipikus felhasználás: return wantarray ? () : undef;
warn LIST Egy figyelmeztető üzenetet ír a szabványos hibakimenetre, de nem áll le, mint a die. write FILEHANDLE write EXPRESSION
A Perl programozási nyelv – röviden
79/79
write Egy formátumozott, és akár többsoros rekordot ír a FILEHANDLE fájlkezelőhöz rendelt fájlba. A formátum alapértelmezés szerint az a formátum, amelynek ugyanaz a neve, mint a fájlkezelőnek, de a pillanatnyi kimenti csatornához (select) formátumot lehet rendelni: a $~ változónak a formátum nevét kell adni értékként. A lapteteje automatikusan kezelődik, ha nincs elegendő hely az oldalon a rekord számára, akkor egy lapdobást ír ki a fájlba, majd a lap teteje fejlécet, és utána az aktuális rekordot. Alapértelmezés szerint a fejléc a fájlkezelő neve, amelyhez a _TOP karaktereket adja hozzá a rendszer, de tetszőlegesen átállítható, csupán a $^ változóhoz kell a formátum nevét rendelni, miközben a fájlkezelő van kiválaszva a select függvénnyel. A lapon fennmaradó sorok száma a $- változóba kerül, amelynek nulla értéket adva lapdobást lehet elérni a következő kiírásnál. Ha a FILEHANDLE nincs megadva, akkor a kiírás az aktuális kimeneti csatornába megy, amely alapértelmezés szerint STDOUT, de megváltoztatható a select függvénnyel. Ha a FILEHANDLE helyett egy kifejezés van megadva, akkor a kifejezés adja meg a fájlkezelő nevét. Megjegyzés: a write NEM a read ellentéte. y/// A transzlációs operátor (ugyanaz, mint tr).