*

Perl Magyarul

A mottók: "Mindenhez több mint egy út vezet."
A programozó három fõ erénye a Lustaság, a Türelmetlenség és az Önhittség.
Mottó után megnézhetjük, hogy egyáltalán mirõl lesz szó:
  1. Perl 5 nyelv rövid összefoglalása
  2. Indulás
  3. Adatstruktúrák
  4. Szintaxis ... utasítások
  5. Operandusok és precedenciájuk
  6. RegExp - szövegelés
  7. Beépített függvények
  8. Elõre definiált változók
  9. Alprogramok írása
  10. Modulok
  11. Bonyolultabb struktúrák
  12. OOP
  13. Ami hiányzik a nyelvbõl
  14. Ötletek

Perl 5 nyelv rövid összefoglalása

A Perl nyelv elsõ verzióját 1991-ben készítette el Larry Wall, a NASA támogatásával. A nyelvet elsõsorban szöveg feldolgozásra szánták. Sokkal fontosabbnak tekintették a hatékonyságot mind a kód megírásában, mind a kész program futtatásakor, mint a szépséget. A nyelv neve is a fentebb elmondottakra utal, hiszen a Perl a "Practical Extraction and Report Language" -bõl képzett betûszó. Igaz, az Larry Wall elõször "Pathologically Eclectic Rubbish Lister"-nek titulálta.

A nyelv nagy elõnye a platformfüggetlenség: létezik az összes U*X-ra, VMS-re, OS/2-re és az M$ termékeire is.

A Perl nyelv egy interpretált - illetve betöltéskor fordított - nyelv. Eredetileg rendszeradminisztrációs feladatok megkönnyítésére írta Larry Wall, mert nem volt kedve a meglévõ eszközök korlátaival bajlódni. A nyelv meglévõ eszközökre lett alapozva: C, sed, awk és sh programokra. Szerintem a LISP ismerete is sokat segíthet a listakezelések megértésében.

Perl-ben csak a számítógép hardware korlátai érvényesülnek: egy teljes file-t képes beolvasni egy string változóba (ha van elég memória), tetszõleges mélységû rekurzió futtatható benne (ha van türelmünk és memóriánk). Asszociatív tömbök elérését hash táblákkal gyorsítja (ami meglepõen hatékony programok írását teszi lehetõvé). Nagyon gyors és rugalmas mintaillesztõ algoritmusa van szövegek keresésére és cseréjére. Képes bináris adatokkal is dolgozni, és ezekbõl bonyolult adatstruktúrákat felépíteni. Az adminisztrációs feladatok megkönnyítésére az aszociatív tömbökhöz adatbázis file-okat rendelhetünk, melyek szerkezetét egy gyakorlott programozó maga is megadhatja.

Az 5-ös verziótól kezdve már használhatjuk a moduláris programozást támogató nyelvi konstrukciókat, sõt már Objektum Orientált eszközöket is.

A Perl-ben setuid programok sokkal biztonságosabban írhatók, mint C nyelvben az adatfolyam követését biztosító funkciók miatt (ld.: -T kapcsoló). Elkerülhetünk egy csomó egyszerû hibát, amit a C programban csak debuggolással fedeznénk fel. Egyszerûen sokkal jobb a fejlesztési idõ/futtatási idõ arány, ha egy ritkán használt, vagy futási idõben nem kritikus program írásánál. Szerintem akkor is érdemes ehhez a nyelvhez fordulni, ha egy shell script-ekbõl és C programokból álló keveréket szeretnénk létrehozni, vagy csak tesztelni szeretnénk egy ötletünket, amit - ha beválik - persze késõbb megírhatunk C-ben.

Fontos még megjegyezni, hogy a Perl POSIX kompatíbilis.

Ez a leírás UNIX rendszert használó gépeken használható fel igazán. A konkrét nyelvi részek a DOS, OS/2 és Windows alatt futó Perl interpreterekre is igaz, de a környezetfüggõ részek és a példák csak UNIX alapú rendszereken mennek.

Ennyit a "rövid" összefoglalásról...

Indulás

Kezdetnek mindjárt megnézhetjük a minimális Perl programot, ami a "Hello World!!!" szöveg kiírásához kell:
        #!/usr/local/bin/perl

        print "Hello World!!!\n";
Már ebbõl a picike programból egy csomó hasznos dolgot meg lehet tudni:
  • A Perl program egy egyszerû szövegfile, és követi a shell scriptek gyakorlatát a "#" karaktert használva a megjegyzések jelölésére. Itt ez az elsõ sorban egy speciális jelentéssel is bír, hiszen az elsõ sorba írt "!" kezdetû megjegyzés a script interpreterét határozza meg. Ha ez nem lenne ott, akkor a perl <programnév> paranccsal lehetne lefuttatni.
  • Látható, hogy a kiíratás egy egyszerû print utasítással megadható, és az utasítást mindig egy ";" zárja be.
  • A szövegek egy C programhoz hasonlóan itt sem tartalmaznak implicit sorvége jelet - ezt a megszokott módon nekünk kell kiírni. (Sor beolvasásakor viszont nem vágja le a sorvége jelet, így azt is a programozónak kell kezelnie.)

Adatstruktúrák

Három alapvetõ adatstruktúra található a nyelvben: skalár, skalárok tömbje és az asszocitív tömb. Ezeket - mint azt késõbbiekben látni fogjuk - mutatókkal is lehet kombinálni, így lényegében mindenféle adatstruktúrát megalkothatunk. A normál tömbök indexe - általában - 0-val kezdõdik. Az asszociatív tömböket szövegekkel kell indexelni.

A változó nevének elsõ karaktere határozza meg annak típusát:

  • $ skalárokat,
  • @ számmal indexelt és a
  • % asszociatív tömböket jelöl.
Ez az elsõ karakter a változónak a kifejezésben betöltött szerepét kell, hogy takarja.

Példák:

        $days           # egyszerû skalár
        $days[3]        # days nevû tömb negyedik eleme
        @days           # az egész tömb ($days[0], .. , $days[$#days])
        $days{'Feb'}    # days nevû asszociatív tömb egy eleme
        %days           # az egész asszociatív tömb (kulcs, érték párok)
        $#days          # days tömb utolsó indexe
Az alprogramokat még a & jellel is megjelölhetjük. Erre akkor lehet szükség, ha az alprogramot deklarációja elõtt szeretnénk használni. Függvényre a deklarációja után már a & szimbólum nélkül is hivatkozhatunk (ez - a nyelv elõzõ verziójától eltérõen - minden függvényre alkalmazható).

A változók nevei egyébként a típusuknak megfelelõ külön szimbólumtáblába kerülnek, tehát használhatunk azonos nevû tömböt, asszociatív tömböt és skalárt. (Ekkor $ize[0] az @ize tömb része, nem pedig az $ize változót helyettesíti.)

A változók nevei betûvel kell hogy kezdõdjenek, és tetszõleges alfanumerikus karakterrel, illetve aláhúzásjellel folytatható. A változó neve nem kell, hogy megadott legyen, akár egy kifejezés is állhat helyette, melynek aktuális értéke lesz a valódi név!

Vannak speciális változónevek alapvetõ paraméterek jelölésére. Ezek az

  • Elõre definiált változók részben megtalálhatóak.
  • Környezet

    A kifejezés típusa a kifejezés környezetétõl is függhet!

    Például az int(<STDIN>) eredménye egy egész szám lesz, amit a bemenet egy sorából állít elõ az int függvény, de a sort(<STDIN>) eredménye egy lista lesz, amit a bemenet összes sorának beolvasása után a sort függvény rendezéssel állít elõ!

    Skalárok

    Skalár változók sokféle értéket tárolhatnak: szám, szöveg, bináris adat vagy mutató. A tartalom a használat során mindig szükséges formára alakul, azaz kiírhatunk egy számot szövegként egy változóba, majd ezt a változót megszorozhatjuk kettõvel.

    Az aritmetikai mûveleteknél a számok bináris formára konvertálódnak, így ezek pontosságát a processzor korlátozza. Vannak persze kiegészítõ modulok tetszõleges pontosságú számok kezelésére is.

    Feltételek vizsgálatánál csak az üres szöveg, illetve a 0 érték jelent hamisat.

    A skalár változóknak alapvetõen két állapota lehet: definiált, vagy definiálatlan. Ezeket a defined, illetve undefined függvényekkel kérdezhetjük le. Egy változó addig definiálatlan, amíg valaki nem ad neki értéket, vagy nem definiálja explicit módon. Definiálatlan változónak - a környezetétõl függõen - 0 vagy üres szöveg értéke van.

    Példák:

            $i = 2;                         # egész
            $f = 2.3;                       # racionális
            $szam = 1000000000;             # ez egy nagy egész
            $hexa = 0xffeedd;               # hexadecimális szám
            $szoveg = "Ez egy szoveg";      # egy szöveg
            print "Valami\n";               # egy szöveg megjelenítése
            print <<VEGE;                   # hosszabb szöveg megjelenítése
    
            Valami                          # "Itt a dokumentum" stílusú
            VEGE                            # adatbevitellel
            $szoveg = <<VEGE;               # $szoveg = "ez is szoveg\n"
            ez is szovega                   # ez is megy
            VEGE
            fv(<<EGY, <<KETTO);             # sõt ez is!
            elso parameter
            EGY
            masodik parameter
            KETTO

    Tömbök

    A Perl-ben használt tömböket inkább indexelt listáknak kéne nevezni a kiterjeszthetõségük miatt. Ha bármelyik típusban egy eddig nem létezõ elemnek adunk értéket az automatikusan definiálódik. A tömböket persze nem csak elemenként lehet feltölteni:
            @tomb = ('elso', 2, $harom);    # háromelemû tömb
            %szinek = (                     # asszociatív tömb
                    'piros' => 0x00f,
                    'kék' => 0x0f0,
                    'zöld' => 0xf00,
                    );
    Értékadásokban (rész)tömböket is értékül adhatunk. Ezekben az esetekben a balérték listája az elsõ elemtõl kezdve addig töltõdik fel, amíg van új elem a jobb oldalon.
    Tömbök tömbje nem létezik perlben, így a (@foo1, @foo2, @bar) a @foo1 , @foo2 és a @bar ltömb kompozíciója, míg a ((), () , ()) és a () ugyan azt - az üres tömböt - jelentik.

    Szintaxis ... utasítások

    A Perl program utasítások és deklarációk egymásutánja, amelybe megjegyzéseket a # jel használatával tehetünk. Ennek hatására a Perl interpreter a sor végéig lévõ szövegrészt megjegyzésnek tekinti.

    A nyelvben az utasítások és deklarációk szabadon - akár keverve is, mint egy C++ programban - követhetik egymást. Megkötés csak az alprogramok hívására van: a még nem deklarált alprogramot csak a & szimbólum használatával lehet meghívni.

    Egyszerû utasítás

    Egy utasítás egy pontosvesszõvel lezárt jelsorozat lehet. Ezekbõl több is szerepelhet egy sorban. Egy utasítás után egy módosító kifejezés állhat, amely ennek az egyetlen utasításnak a hatását befolyásolja:
            utasítás if EXPR
            utasítás unless EXPR
            utasítás while EXPR
            utasítás until EXPR
    Egy üzenet kiírása feltételtõl függõen:
            print "Hello kedves olvasó!\n" if $bobeszedu_program;

    Összetett utasítás

    Itt kell megemlíteni a BLOKK fogalmát, amely { és } jelekkel közbezárt utasítássorozat. (Itt fontosak a { és } jelek, még egyetlen utasításnál is!)

    Ez alapján a lehetséges formák:

            if (EXPR) BLOKK
                    # BLOKK végrehajtódik ha az EXPR igaz
            if (EXPR) BLOKK1 else BLOKK2
                    # ha EXPR igaz akkor BLOKK1, egyébként BLOKK2
                    # lesz végrehajtva
            if (EXPR) BLOKK elsif (EXPR) BLOKK ... else BLOKK
    Az if utasítás szintaxisa itt egyértelmû lesz, mivel a BLOKK nem állhat egyetlen utasításból.
            CIMKE while (EXPR) BLOKK
            CIMKE while (EXPR) BLOKK continue BLOKK
    A while ciklus törzsében végrehajtott next utasítás hatására a vezérlés a continue BLOKK-ra kerül, majd újra elindul a ciklusmag.
            CIMKE for (EXPR1; EXPR2; EXPR3) BLOKK
    Ez a szokásos C-beli ciklus formája.
    A következõ két forma ekvivalens:
            for($i = 1; $i < 10; $i++) {            $i = 1;
                ...                                 while($i < 10) {
            }                                           ...
                                                    } continue {
                                                        $i++;
                                                    }
            CIMKE foreach változó (TOMB) BLOKK
    Ez a shell-ekben meglévõ ciklus egy változata. Itt a változó sorban felveszi a TOMB elemeit értékül, és így indul el a ciklusmag.
            CIMKE BLOKK continue BLOKK
    Ez a végtelen ciklus volt...

    A switch utasításra nincs külön forma, de van rá egypár lehetséges más megoldás, például:

            SWITCH: {
                /^abc/ && do { $abc = 1; last SWITCH; };
                /^def/ && do { $def = 1; last SWITCH; };
                /^xyz/ && do { $xyz = 1; last SWITCH; };
                $nothing = 1;
            }
    Ahol a last utasítás a megnevezett BLOKK elhagyására szolgál. A /^abc/ alakú feltételek mintaillesztésre szolgálnak. Ha egy minta illeszkedik a $_ változó tartalmához, akkor a hozzá tartozó feltétel második tagja is kiértékelésre kerül, azaz a do blokk is végrehajtódik.

    Operandusok és precedenciájuk

    A C nyelvben érvényes szabályok érvényesek, és még van egypár - shell script-ekbõl ismerõs - új operátor.
    operátor  kiértékelés iránya  leírás 
    lista (,)  balról jobbra  kifejezések listája 
    ->  balról jobbra  hivatkozás 
    ++,--  nem asszociatív  növelés, csökkentés 
    **  jobbról balra  hatványozás 
    !,~,\ és unáris +,-  jobbról balra  nem, bináris nem, címoperátor, +, - 
    =~,!~  balról jobbra  szöveg illeszkedés, nem illeszkedés 
    *,/,%,x  balról jobbra  szorzás, osztás, modulus, ismétlés 
    +, -, .  balról jobbra  összeadás, kivonás, konkatenáció 
    <<,>>  balról jobbra  balra, illetve jobbra shift 
    unáris operátorok  nem asszociativ  pl. file tesztelés -f
    <,>,<=,>=,lt,gt,le,ge nem asszociatív  szám illetve szöveg összehasonlítása
    ==,!=,<=>,eq,ne,cmp  nem asszociatív  szám illetve szöveg összehasonlítása
    balról jobbra  bináris AND 
    |,^  balról jobbra  bináris OR és XOR 
    &&  balról jobbra  logikai AND 
    ||  balról jobbra  logikai OR 
    ..  nem asszociatív  tartomány 
    ?:  jobbról balra  feltételes értékadás 
    =, +=, -=, *= ...  jobbról balra  értékadás operátorai 
    , =>  balról jobbra  vesszõ és kulcs operátor 
    lista operátorok  nem asszociatív  lista manipulációk 
    not  balról jobbra  logikai NEM 
    and  balról jobbra  logikai ÉS 
    or, xor  balról jobbra  logikai VAGY-ok

    Itt csak az ismeretlennek tûnõ operátorokat fogom kiemelni:

    címoperátor
    olyan mint a C nyelv & operátora; visszaadja az operandus objektum címét (alprogramokra is megy!)
    ismétlés
    egy szöveget meg lehet ismételni néhányszor, pl.: "ha"x3 == "hahaha"
    konkatenácó
    szövegek összefûzése, pl.: "ha"."ha" == "haha"
    file tesztelés
    ezek a shell programokban megszokott file tesztelõ operátorok, pl.: -f "hello.c" akkor igaz, ha a hello.c file létezik
    szöveg összehasonlítás
    Erre a lt,gt,le,ge,eq,ne operátorok szolgálnak. Ha szövegeket az == operátorokkal hasonlítgatjuk, akkor azok memóriabeli címei kerülnek összehasonlításra, nem tartalmai!

    cmp értéke -1, 0, vagy 1 lehet a szövegektõl függõen.
    szám összehasonlítás
    Szokásos operátorokon kívül a <=> szerepel itt. Ennek -1 az értéke, ha az elsõ szám nagyobb, 1, ha a második, és 0, ha egyenlõ a két szám. Ez az operátor - az elõbb említett cmp operátorhoz hasonlóan - fõleg rendezéseknél használható jól.
    I/O
    Az alapvetõ és legfontosabb I/O operátor a < és a >. Ha egy file leíróját ilyen jelek közé rakjuk, akkor egy sort olvashatunk belõle. A beolvasott sor automatikusan a $_ változóhoz rendelõdik, ha nem adunk meg mást.


    Egy egyszerû cat (UNIX cat parancs) így is leírható:

            while(<STDIN>)
            {
                    print $_;  # print; is lehetne, hiszen az $_ az
                               # alapertelemezett argumentum
            }
    

    A szövegekhez még járul egypár "idézõjel" operátor

    általában  hivatalos jelölés  értelme  megjegyzés 
    '' q{} szöveg literál ez a "szó szerinti" szöveg literál
    "" qq{} szöveg literál változókat helyettesíti a szövegben
    `` qx{} parancs az adott szöveget, mint egy shell parancssort végrehajtja
    qw{} a szövegbõl egy szólistát csinál pl.: paraméterátadás
    // m{} mintaillesztés változókat értékükkel helyettesíti
    s{}{} csere változókat értékükkel helyettesíti
    tr{}{} betûcsere az szövegeket mint cseretáblát használja

    Mintaillesztés

    Szövegkeresés netovábbja.

    Használat

    A mintaillesztést több dologra is lehet használni a =~ vagy a !~ operátorokkal:
    • Szövegrészek felismerésére: egy szövegben a grep programhoz hasonlóan kereshetünk szövegeket.

    • Pl.: $sor =~ /keresettszo/;
    • Szövegekben a sed-hez hasonlóan lecserélhetünk egyes részeket.

    • Pl.:$sor =~ s/eredeti/ujszo/;
    • Szövegekbõl kikereshetünk minket érdeklõ részeket, és azokat szelektíven ki is nyerhetjük (mint az awk-ban). Pl.:($erdekes_szo) = /\s+(\w+) $/;

    Módosítók

    A // után általában írhatunk valamilyen karaktert, ami a keresést egy kicsit módosítja:
    kis- és nagybetûket nem különbözteti meg
    többsoros szövegben keres
    a szöveget egyetlen sorként kezeli
    kibõvített keresési mód

    Az i módosító használatával így a /perl/i kifejezés a PeRL szövegre is illeszkedni fog.

    Az x módosító tulajdonképpen arra jó, hogy egy kicsit lazább szintakszissal írhassuk le a keresõ kifejezéseket. Ezzel már lehetõség van többsoros, sõt megjegyzésekkel tûzdelt kifejezés írására is!

    Regular Expressions, reguláris kifejezések

    Egy ilyen kifejezésben egy szöveghez illeszthetõ mintát lehet leírni. Ebbe a mintába persze belevehetünk extra dolgokat is, hogy a nekünk szükséges részt nyerjük ki a szövegbõl. (A UNIX grep parancsában megszokott dolgok a () csoportosító operátortól eltekintve.)

    Az alapok
    a következõ karakter speciális
    a sor elejéhez illeszkedik
    egy tetszõleges karakterhez illeszkedik (kivéve az újsort)
    sor végéhez illeszkedik
    alternatívák jelölése
    ()  csoportosítás
    []  karakter-osztály kijelölése

    A . csak akkor fog az újsor karakterhez illeszkedni, ha erre az s módosítóval külön megkérjük, pl.:

            $szoveg = <<VEGE;
            Tobbsoros szoveg, amelyben a PERL
            perl szavakat kell majd megtalalni.
            VEGE
    
            print "illeszkedik/s\n" if $szoveg =~ /PERL.perl/s;     # igaz
            print "illeszkedik/\n" if $szoveg =~ /PERL.perl/;       # hamis
    A sor eleje és vége inkább rekord elejét és végét jelenti, hiszen a nyelvben meg lehet határozni, hogy mi válassza el a sorokat ($*). Alapesetben ez persze az újsor karakter, de ezt meg lehet változtatni...

    karaktersorozatok Egy egyszerû kifejezés ismétlõdését a következõkkel lehet jelölni:
    0 vagy több
    1 vagy több
    0 vagy 1
    {n}  pontosan n-szer
    {n,}  n-szer vagy többször
    {n,m}  n <= ismétlõdések száma <= m

    Alapértelmezés szerint ekkor a leghosszabb ismétlõdés fog illeszkedni ezekhez a részekhez. Ha minimális számú illeszkedést szeretnénk, akkor mindegyik után odatehetjük a ? jelet:

            "hhhhhh" =~ /h{2,4}/;   # itt "hhhh" fog illeszkedni
            "hhhhhh" =~ /h{2,4}?/;  # itt csak "hh"

    Speciális karakterek

    \t  tabulátorjel
    \n  újsor
    \r  return
    \f  form feed
    \v  vertical tab
    \a  csengõ
    \e  escape
    \033  oktális számrendszerben megadott karakter
    \x1b  karakter hexadecimálisan
    \c[  kontrol karakter
    \l  kisbetû
    \u  nagybetû
    \L  kisbetû \E-ig
    \U  nagybetû \E-ig
    \E  ...
    \Q  metakarakterek normálisak \E-ig
    \w  "szó" karakter (alfanumerikus és _)
    \W  nem-szó karakter
    \s  whitespace
    \S  nem whitespace
    \d  számjegy
    \D  nem számjegy
    \b  szóhatárhoz illeszkedik
    \B  nem szóhatár
    \A  string elejéhez illeszkedik
    \Z  string vége
    \G  oda illeszkedik, ahol az elõzõ illesztés véget ért

    Az x módosító használatával még lehet használni más dolgokat is, de ezek szerintem már csak igen-igen ritkán kerülnek elõ.

    Csoportosítás

    Ha egy szövegbõl részeket ki akarunk nyerni, akkor a () karaktereket kell használnunk. Ha ezekkel bezárunk egy karaktersorozatot a reguláris kifejezésben, akkor az ahhoz illeszkedõ karakterekre a kifejezésen kívül is hivatkozhatunk.

    Ha egy csere környezetben használjuk, akkor az így kapott karaktersorozatokra a $1, $2, $3 ... változókkal lehet hivatkozni:

            s/^([^ ]*) *([^ ]*)/$2 $1/;         # elsõ két szó felcserélése
            if(`date` =~ /(..):(..):(..)/) {    # idõ kiírása
                    print "ora: $1, perc: $2, masodperc: $3\n";
            }
    Ha lista környezetben használjuk az illesztést, akkor a kiválasztott értékeket közvetlenül is megkaphatjuk:
            ($ora, $perc, $masodperc) = (`date` =~ /(..):(..):(..)/);

    Beépített függvények

    Ez a rész iszonyú nagy, és csomó olyan információt tartalmaz, amit már amúgy is ismer az ember (legalábbis a C programokban használta már õket). Itt csak néhány speciális dolgot fogok ismertetni, ami Perl jellegzetesség.

    Ha valaki ismeri a szokásos C függvényeket, akkor azokat bátran használhatja, biztosan megvannak. Ha nem úgy viselkedik, ahogy várta, akkor érdemes igénybe venni a POSIX modult:

            use POSIX;
    Ezek után már biztosan meglesz az összes POSIX függvény.

    Ha valakinek még ez sem elég, akkor igénybe veheti a különbözõ modulokat. Már a nyelvvel együtt lehet találni adatbáziskezelõ kiterjesztésektõl kezdve a terminálkezelõ függvényekig sok mindent. Ezeken kívül az Internetben legalább száz új modul kínál kiterjesztéseket különféle nyelvek és könyvtárak felé (pl.: SQL adatbázikezelés, X11 grafikus felület, Prolog...).

    néhány függvény...

    bless REF,PACKAGE
    A REF referenciát egy PACKAGE modulban leírt objektumként fogja kezelni. Lényegében ez az útja egy új objektum létrehozásának.
    caller
    Megmondja, hogy ki hívta az aktuális kódrészletet...

    ($package, $filename, $line) = caller;
    chop
    Levágja a '\n' jelet a sor végérõl. Ez sorok olvasása után hasznos.
                    while(<>) {
                            chop;   # $_ végérõl vág
                            ...
                    }
                    chop($cwd = `pwd`);     # aktuális könyvtár
    
    defined EXPR
    Megmondja, hogy egy EXPR változó definiált-e.
    delete EXPR
    Egy elem törlése egy asszociatív tömbbõl, pl.: delete $tomb{"eleme"};
    die LIST
    Ez lényegében a C könyvtári exit() függvény, csak a LIST tartalmát még kiírja mielõtt kilép a programból.
    dump LABEL
    Egy core dump! Ha a core dump eredményeképpen kapott file-t futtatjuk, akkor az a LABEL cimkénél fog elindulni.

    Ez a módja egy Perl prgram "fordításának".
    each ASSOC_ARRAY
    Egy asszociatív tömb elemeit iterálja:
                    while(($key,$value) = each %ENV)
                    {
                            print "$key=$value\n";
                    }
    
    környezeti változók kiírása (ld. még a változókat)
    eval BLOCK
    A BLOCK futtatása az aktuális környezetben. A BLOCK egy string is lehet!
    exists EXPR
    Megmondja, hogy létezik-e az asszociatív tömb egy eleme, pl.: if exists $tomb{"eleme"} ...
    glob EXPR
    EXPR file-név teljesen kiterjesztve. Úgy mûködik, mint a shell-ek file-név kiterjesztõ algoritmusa.
    keys ASSOC_ARRAY
    ASSOC_ARRAY kulcsait adja vissza egy tömbben.
    local EXPR
    EXPR-ben felsorolt változók a blokkra nézve lokálisak lesznek. Ez a dinamikus láthatóság. Használatakor az interpreter egy verembe menti az azonos nevû globális változót, majd a blokk végén visszatölti.
    my EXPR
    EXPR-ben lévõ változók csak az aktuális blokk-ban lesznek láthatóak. A local-tól eltérõen ez fordítási idõben értékelõdik ki, tehát a változónevekben nem lehetnek mágikus karakterek. Az így definiált változók inkább a C nyelv statikus lokális változóihoz állnak közel, mert a külvilág számára teljesen láthatatlanok lesznek, illetve rekurzió esetén is csak egyszer jönnek létre, két hívás között pedig megõrzik az értéküket
                    sub kiir 
                    {
                            my ($szoveg1, $szoveg2) = @_;
                            chop $szoveg1;
                            chop $szoveg2;
                            print $szoveg1, ':', $szoveg2, '\n\n';
                    }
    
    open FILEHANDLE, EXPR
    EXPR-ben leírt file megnyitása a FILEHANDLE leíróba.
                open(FILE,"valami.txt");        # írás-olvasás
                open(BE,"</etc/passwd");        # olvasás
                open(KI,">/tmp/output");        # írás
                open(FINGER,"finger @augusta |"); # olvasás pipe-ból
                open(RENDEZ,"| sort >/tmp/ki");# írás pipe-ba
    
    Az így megnyitott file-okat a close-val lehet lezárni, és I/O mûveletekben lehet használni:
                print FILE "Egy szor\n";  # "Egy sor" írása a FILE-ba
                $sor = <BE>                     # sor olvasása
    
    pack MINTA,LIST
    A LIST tartalmát a MINTA szerint binárisan összepakolja. Fõleg külsõ eljárások hívása elõtt kell megtenni.
    print FILEHANDLE LIST
    Kiírás általános utasítása. A FILEHANDLE elhagyható, ekkor a standard kimenetre ír ki. A FILEHANDLE és a LIST között nem lehet vesszõ!
    return
    Alprogramból érték visszaadása. Ha ez nem szerepel, akkor az alprogram utolsó utasításának értéke lesz visszaadva.
    shift LIST
    A LIST tömböt elmozdítja egy elemmel lefele. Az elsõ elemmel tér vissza, és az törlõdik is abból.
    sort LIST, vagy sort SUBNAME LIST
    LIST rendezése lexikografikusan, vagy a SUBNAME-ben definiált alprogramnak megfelelõen. A SUBNAME alprogramnak egy érvényes összehasonlításnak kell lenni.
    study SCALAR
    Az adott változó tartalmát tanulmányozza egy kicsit, hogy késõbb több mintaillesztést hatékonyabban végezhessünk el rajta. Ez tényleg csak akkor jó, ha több mintaillesztést használunk ugyanarra a változóra!
    tie VARIABLE,PACKAGENAME,LIST
    Az adott változót hozzárendeli a PACKAGENAME-ben leírt struktúrához. Ezzel lehet egy egyszerû asszociatív tömbhöz hozzárendelni egy adatbázist, ahol a tömb indexei lényegében keresési kulcsok lesznek.

    A PACKAGENAME modulban a változó típusától függõen különbözõ függvényeket kell megírni:
    • asszociatív tömb
      • TIEHASH objectname, LIST
      • DESTROY this
      • FETCH this, key
      • STORE this, key, value
      • DELETE this, key
      • EXISTS this, key
      • FIRSTKEY this, key
      • NEXTKEY this, key
    • tömb
      • TIEARRAY objectname, LIST
      • DESTROY this
      • FETCH this, key
      • STORE this, key, value
    • skalár
      • TIESCALAR objectname, LIST
      • DESTROY this
      • FETCH this
      • STORE this, value
    undef EXPR
    EXPR változó megszüntetése
    untie VARIABLE
    Egy tie kapcsolat megszüntetése.
    unpack
    pack függvény ellenkezõje
    use MODULE, LIST
    MODULE modul LIST-ben felsorolt nevei láthatóvá válnak az aktuális package-ban. Ha a LIST elmarad, akkor a MODULE által exportált változók válnak láthatóvá.

    A no kulcsszó a use ellentettje, azaz a láthatóságot megszünteti.
    wantarray
    Igaz lesz az értéke, ha a végrehajtás alatt álló alprogram visszatérési értékét egy listához akarjuk rendelni. Ezzel a függvényhívással az alprogram lényegében meg tudja nézni, hogy milyen környezetben hívták meg õt, és ettõl függõen akár más-más típusú visszatérési értéke is lehet!
    warn LIST
    Mint a die, csak nem lép ki a programból.

    Elõre definiált változók

    awk-on nevelkedett emberek itt otthon érezhetik magukat.
    Ha az awk-os neveket szeretnénk használni, akkor a
            use English;
    sort kell még beírni a programba.

    A file-ok "objektum-szerû" használatához a

            use FileHandle;
    sort kell beírni. Ezek után a következõk ekvivalensek:
            print KIMENET "Hello World!!!\n";
            KIMENET->print("Hello World!!!\n");
    A változókból itt is csak a legfontosabbakat fogom megemlíteni:
    $_,$ARG
    Az alapértelmezett változó. Ha valahol nincs változó, akkor ott ez lesz használva.
    $1,$2,$3...
    Reguláris kifejezésekbõl kapott betûcsoportok.
    $&, $MATCH
    Legutolsó mintaillesztésnél az illesztett rész.
    $`, $PREMATCH
    Legutolsó mintaillesztésnél a $& elõtti rész.
    $', $POSTMATCH
    Legutolsó mintaillesztésnél a $& utáni rész.
    $., $NR
    Utolsó olvasási mûveletnél az olvasott sor sorszáma. (Ez csak olvasható változóként kezelendõ!)
    $/, $RS, $INPUT_RECORD_SEPARATOR
    Input rekordok elválasztása. Ez alapesetben az újsor karakter, de bármire lecserélhetõ. Ha az üres stringet adjuk meg, akkor üres sorok lesznek a határok. Ez nem ugyanaz mint $/ = "\n\n";, mert a $/ = "\n\n"; több üres sort is egyetlen határnak tekint.
    $|, $OUTPUT_AUTOFLUSH
    Output bufferelését szünteti meg, ha az értéke nem egy.
    $\, $ORS, $OUTPUT_RECORD_SEPARATOR
    Az a karakter, amit a print ki fog írni minden sor végén. Ez alapesetben üres.
    $?, $CHILD_ERROR
    Utolsó gyermek process visszatérési értéke. Ez a wait() függvény visszatérési értéke, tehát a valódi exit() értéket ($? >> 8)-ként kaphatjuk meg.
    $$, $PID, $PROCESS_ID
    A process azonosító száma.
    $<, $UID, $REAL_USER_ID
    Valódi user azonosítója.
    $>, $EUID, $EFFECTIVE_USER_ID
    A futás közbeni jogok tulajdonosa. Ez az érték csak a setuid programoknál vált át a file tulajdonosának jogaira.

    Ez persze írható változó, tehát a $> = 0; a root-tá válás egy módja, csak ez nem mindig fog bejönni :-).
    $(, $GID, $REAL_GROUP_ID
    Valódi csoport azonosítója. Ha a rendszer több csoportot is támogat egyszerre, akkor ez egy listája azoknak a csoportoknak, amiben a process benne van.
    $), $EGID, $EFFECTIVE_GROUP_ID
    Effektív csoport azonosítója. Ez setgid program futtatásakor különbözhet az elõzõtõl.
    $0, $PROGRAM_NAME
    A programot indító parancs neve (egy Perl script-nél a script neve, nem a "perl" szó).
    @ARGV
    A parancssori argumentumok listája.
    @INC
    Azon könyvtárak listája, ahol a Perl elkezd keresgélni egy modul után.
    %INC
    A használt modulok tömbje (filenév,elérési-út) elemekkel.
    %ENV
    Környezeti változók tömbje, pl.:
                    print "Otthonom: ", $ENV{"HOME"}, "\n";
    
    %SIG
    Kivételkezelõk tömbje.
                    sub handler {   # az elsõ paraméter a signal neve
                            local($sig) = @_;
                            print "Elkaptam $sig-t!\n";
                            exit(0);
                    }
                    $SIG{'INT'} = 'handler';
                    $SIG{'QUIT'} = 'handler';
               &nb>
    

    Átvitel megszakítva!

    p;              $SIG{'INT'} = 'DEFAULT';  # alapértelmezett                 $SIG{'QUIT'} = 'IGNORE';  # figyelmen kívül hagy
    Néhány Perl-beli esemény is kezelhetõ így. A $SIG{__WARN__} a warn által kiváltott, a $SIG{__DIE__} pedig a die által kiváltott esemény lekezelésére szolgál. Mindkét esetben átadásra kerülnek a warn, illetve a die paraméterei.

    Alprogramok írása

    Alprogramok deklarálása:

            sub NEV;        # a NEV ismertté tétele
            sub NEV BLOCK   # deklarálás és definíció
    Egy alprogramot nem kell elõre deklarálni ahhoz, hogy használhassuk. Az alprogramoknál a paraméterlistát sem kell deklarálni, mert ez változhat. A hívott alprogram a paramétereket a @_ listán keresztül kapja meg. Az alprogram utolsó utasításának az értéke lesz a visszatérési érték, hacsak nincs egy return utasításban más megadva.
            sub max { 
                    my $max = pop(@_);
                    foreach $elem (@_) {
                            $max = $elem if $max < $elem;
                    }
                    $max;
            }

    Alprogram hívása:

            &NEV;           # az aktuális @_-t adja tovább
            &NEV(LISTA);    # Ha &-t írunk, akkor () kötelezõ
            NEV(LISTA);     # & elhagyható ha van () vagy már deklarált
            NEV LISTA;      # () elhagyható, ha a NEV már deklarált
    Alprogram hívása akkor megy ilyen egyszerûen, ha az az õt tartalmazó modulban látható. Ha ettõl eltérõ modulban lett deklarálva, akkor modulhivatkozással, vagy valamilyen objektum-orientált technikával kell meghívni a kívánt eljárást (ld. késõbb).
            $m = &max(1,2,3);       # a hatás ugyan az
            $m = max 1 2 3;

    Névtelen alprogram létrehozása:

            $alpref = sub BLOCK;    # deklarálás
    
            &$alpref(1,2,3);        # hívás
    Ez a technika fõleg egyszer használatos alprogramoknál lehet hasznos, például egy signal kezelõ átdefiniálásakor.

    Modulok

    Ja kérem, ez egy "komoly" nyelv!

    package

    A Perl nyelv lehetõséget ad különbözõ léthatósági körök használatára. Ezeket a láthatósági köröket moduloknak nevezhetjük, amelyet a package kulcsszó vezet be. A package hatása az adott blokk végéig, vagy a következõ package-ig tart.

    Alap esetben egy egyszerû programban minden a main modulba kerül be. Ha leírjuk a package szót, akkor az ez után következõ deklarációk már az új modulba fognak tartozni. A modul neveihez a :: hivatkozás operátorral férhetünk hozzá (ez régen egy ' jel volt, de az egyszerûbb olvashatóság érdekében, meg a C++ programozók kedvéért ez megváltozott).

            $elso = 1;      # ez a $main::elso
    
            package MODUL;  # uj modul kezdete
    
            $masodik = 1;   # $MODUL::masodik
            $elso = 1;      # $MODUL::elso
    
            $main::elso = 2;# $main::elso
    A fõmodul neveihez még a $::elso hivatkozással is hozzáférhetünk.

    Szimbólumtábla

    A modulok szimbólumtáblái futás közben elérhetõek, sõt módosíthatóak!!!

    A modulhoz a modul nevével megegyezõ szimbólumtábla tartozik, ami lényegében egy asszociatív tömb: %main::, avagy %MODULE::. Az itt lévõ bejegyzésekhez a *nev alakban is hozzáférhetünk.

            local(*main::alma) = *main::korte;
            local($main::{'alma'}) = $main::{'korte'};
    Ez a példa egy új álnév létrehozását mutatja. Ezek után minden korte-re alma-ként is hivatkozhatunk. Az egyetlen különbség az, hogy az elsõ fordítási idõben értékelõdik ki.

    Konstruktor, destruktor

    Itt az awk programozók megint otthon érezhetik magukat. Ha a modulban BEGIN, illetve END kulcsszóval jelzett blokkot definiálunk, akkor azok a package használata elõtt, illetve után lefutnak.
            package hibakezeles;
    
            BEGIN {
                    open(HIBAK,">./hibak");
            }
    
            END {
                    close(HIBAK);
            }
    
            sub kezeles {
                    local ($szoveg) = @_;
                    print HIBAK $szoveg, "\n";
            }
    A programban elindított BEGIN blokkokhoz képest fordított sorrendben fognak lefutni az END blokkok.

    Egy modulban lévõ nevekhez a use kulcsszóval férhetünk hozzá:

            use MODUL;
            use hibakezeles kezeles;
    A use használata ekvivalens a következõvel:
            BEGIN { require MODUL; import MODUL; }
    Modulokat implementáló file-okat az @INC által meghatározott könyvtárakban keresi a rendszer. A .pm, .pl és .ph kiterjesztéseket nem kell kiírni a filenevek után.

    Bonyolultabb struktúrák

    A gondok mindig a mutatókkal kezdõdnek, de ez itt még álnevekkel is kombinálódik...
    Perl 4-ben kicsit nehézkes volt a bonyolult adatstruktúrák kezelése, de most már vannak referenciák, így már mindazt a borzalmat el lehet követni, amit egy C programban csak el tudunk képzelni. Sõt még többet is, mert egy C programban nem lehetett a változóneveket menet közben manipulálni.

    Referencák létrehozása

    Az ötös verziótól kezdve Perlben három fajta referenciát különböztetünk meg: "hard", "soft", és "szimbolikus" referenciákat.
    A soft referenciával egy már meglévõ változóra mutathatunk:
    1. Legegyszerûbb a \ operátor használata. Ezzel egy újabb hivatkozást készíthetünk egy változóra (egy már biztosan van a szimbólumtáblában):
    2.         $scalarref = \$scalar;
              $arrayref = \@ARGV;
              $hashref = \%ENV;
              $coderef = \&handler;
    Hard referenciával egy új objektumot hozhatunk létre:
      # Névtelen dolgokra is lehet hivatkozni:
              $arrayref = [1, 2, ['a', 'b', 'c']];
              $hashref = {
                      'Ádám' => 'Éva',
                      'Clyde' => 'Bonnie',
              };
              $coderef = sub { print "Nem nyert!\n"; };
      
    Hard referenciáknál a Perl egy úgynevezett referenciaszámlálóval dolgozik, amely azt tárolja, hogy hányan hivatkoznak az adott objektumra. Ha ez az érték 0, akkor a garbage collector felszabadítja az adott objektumot. Ez viszont azt jelenti, hogy pl. egy két irányba láncolt lista soha nem fog "kézi segítség" nélkül felszabadulni.

    Referenciák használata

    Nagyon egyszerû egy referenciát használni: a programban egy változó neve helyére bárhova beírhatunk egy megfelelõ típusú referenciát tartalmazó változót.
    1. Az egyszerû esetek, amikor egy egyszerû struktúrát szeretnénk használni:
    2.         $ketto = $$scalarref;
              print "A program neve:",$$arrayref[0],"\n";
              print "HOME=",$$hashref{'HOME'};
              &$coderef(1,2,3);
      
      Persze lehet mutatni mutatóra is:
              $refrefref = \\\"valami";
              print $$$$refrefref;
      
    3. Bármilyen hely, ahol egy referenciát kapnánk meg, helyettesíthetõ egy blokkal, amely értéke a referencia lesz:
    4.         $ketto = ${$scalarref};
              print "A program neve:",${$arrayref}[0],"\n";
              print "HOME=",${$hashref}{'HOME'};
              &{$coderef}(1,2,3);
      
      No persze a blokk lehet bonyolultabb is:
              &{ $inditas{$index} }(1,2,3);   # megfelelõ eljárás indul
              $$hashref{"KEY"} = "VALUE";     # 1. eset
              ${$hashref}{"KEY"} = "VALUE";   # 2. eset
              ${$hashref{"KEY"}} = "VALUE";   # 3. eset
              ${$hashref->{"KEY"}} = "VALUE"; # 4. eset
      
      Itt az 1. és 2., illetve a 3. és 4. eset egyenértékû.
    5. A fenti esetek egyszerûsítésére szolgál a -> operátor:
    6.         print "A program neve:",$arrayref->[0],"\n";
              print "HOME=",$hashref->{'HOME'};
      
      Ennek balértéke bármilyen kifejezés lehet, amely egy referenciát ad vissza. Ez az operátor el is hagyható {} vagy [] zárójelek között (de tényleg csak közöttük!):
              $array[$x]->{"valami"}->[0] = "január";
              $array[$x]{"valami"}[0] = "január";
      
      Ezzel el is jutottunk a többdimenziós C-beli tömbökhöz:
              $tomb[42][4][2] += 42;
      A kódrészre mutató hard referenciáknál fontos megjegyezni, hogy még az ugyanazzal az utasítással generált blokkok is teljesen független eljárásoknak számítanak, pl. a my kulcsszóval definiált változóik különbözõek:
                      
        sub newprint {
          my $x = shift;
          return sub { my $y = shift; print "$x $y\n"; };
        }
        
        
        
        $h = newprint("Hello");
        $g = newprint("Papa");
        .                                            
        .
        .
        &$h("world");
        &$g("mama");
      Ez a következõt fogja kiírni:
        Hello world
        Papa mama

    Szimbolikus referenciák

    Ha a fent említett hivatkozásokban egy blokk nem egy változó referenciájával, hanem egy string-gel tér vissza, a nyelv akkor sem esik kétségbe. Szorgalmasan elkezdi böngészni a szimbólumtáblát, hátha talál egy ilyen bejegyzést:
            $nev = "ize";
            $$nev = 1;      # $ize
            ${$nev} = 2;    # $ize
            ${$nev x 2} = 3;# $izeize
            $nev->[0] = 4; # $ize[0]
            &$nev();        # &ize()
            $modulom = "MAS"
            ${"${modulom}::$nev"} = 5;      # $MAS::ize
    Ha ez a szabadság nem tetszik nekünk, akkor megköthetjük kezünket a use strict; használatával.

    OOP

    Lehet enélkül manapság nyelvet készíteni?
    Amit a Perl objektumokról tudni kell:
    1. Egy objektum csak egy egyszerû referencia, amely történetesen tudja, hogy melyik osztályhoz tartozik.
    2. Egy osztály egy package, amely tudja az objektum hivatkozásokat kezelni, és van némi támogatása az öröklésre.
    3. Egy metódus az egy egyszerû alprogram, amelynek az elsõ paramétere egy objektum referencia lesz.

    Objektum

    Az objektum bármilyen referencia lehet, ami meg van áldva azzal a tudással, hogy hol jött létre:
            package ValamiUj;
            sub new { bless {} }    # 1. verzió
    
            sub new {               # kicsit bonyolultabban...
                    my $self = {};
                    bless $self;
                    $self->initialize();
                    return $self;
            }
    A referencia általában egy asszociatív tömb szokott lenni, amely aztán az objektum saját kis szimbólum táblájaként szolgál...

    Osztály

    Az osztály egy package. Nincs semmi különös jelölés arra, hogy ez egy osztály, sõt még az inicializáló eljárást sem kell new-nak hívni.

    Egy osztályban csak a metódusok öröklésére van támogatás az @ISA tömbön keresztül. Ez egy modul neveket tartalmazó tömb. Ha egy metódust nem található meg az aktuális package-ban, akkor az ebben a tömbben felsorolt modulok lesznek bejárva a hiányzó alprogramért. Ez egy mélységi keresés lesz. Ha itt sem talál semmit, és van egy AUTOLOAD nevû függvény, akkor megpróbálja ezzel elõszedetni a hiányzó eljárást. Ha ez a lehetõség sem járt sikerrel, akkor egy UNIVERSAL-nak nevezett modulban fog keresgélni a rendszer.

    Az @ISA tömb szépsége az, hogy menet közben is lehet módosítani, azaz menet közben megváltoztathatjuk egy osztály leszármazási fáját!

    Metódus

    Semmi különös jelölés nincsen rájuk, kivéve a destruktorokat.

    Alapvetõen kétfajta metódus van:

    statikus metódus
    Ez elsõ paraméterében az osztály nevét kapja meg:
            package ValamiUj;
            sub holvagyok {
                    my ($neve) = @_;
                    print "holvagyok: $neve\n";
            }
    
    Ez a következõképpen hívható:
            ValamiUj->holvagyok();
    
    "rendes" metódus
    Ez az elsõ paraméterében egy referenciát vár.
            package ValamiUj;
            sub new {
                    my $self = {};
                    bless $self;
                    $self->{elso} = 1;  # ez {"elso"}-vel egyenlõ
                    $self->{ize} = 42;
                    return $self;
            }
            sub kiir {
                    my $self = shift;
                    my @keys = @_ ? @_ : sort(keys(%$self));
                    foreach $key (@keys) {
                            print "\t$key => $self->{$key}\n";
                    }
            }
    
    És ennek hívása:
            use ValamiUj;
            $obj = ValamiUj::new();
            $obj->kiir();   # C++ stílus
            kiir obj "elso";        # "print" stílus
    
    Destruktor is definiálható az osztályhoz, ha a modulban megadunk egy DESTRUCTOR nevû eljárást. Ez akkor lesz meghívva, ha a rendszer az objektumhoz tartozó memóriaterületet fel akarja szabadítani.

    Ami hiányzik a nyelvbõl

    • Helyességbizonyítás
    • Absztrakt adattípus
    • Típussal való paraméterezés
    • Kivételes helyzete kezelése
    • Párhuzamos végrehajtás támogatása (Ez egy nem teljesen egyértelmû kérdés. A Perl U*X -okon támogatja az IPC/RPC minden szokásos formáját: támogatja a többszálú végrehajtást, a szálak közötti kommunikációhoz felhasználhatunk pipe-okat, szignálokat, socketeket, szemaforokat, stb. Viszont az egész a U*X operációs rendszerhez kötõdik, az itt megszokott filozófiát követi, az ezen az operációs rendszeren honos technológiával. Ha kihasználjuk, senki nem fogja nekünk garantálni a hordozhatóságot.)


    Ötletek

    Itt csak néhány ötletet mondok el, amik eddigi programjaimban jól jöttek:
    • Ha itt nem volt valami világos, akkor az eredeti - angol nyelvû - Perl dokumentációt érdemes megtekinteni. Ott egyes részek sokkal részletesebbek.
    •         perldoc perl            # avagy
              man perl                # avagy
              netscape http://augusta.inf.elte.hu/langs/perl/perl.html
      
    • A Perl programok végét az __END__ sor is lezárhatja. Ezek után beírhatjuk a program dokumentációját, így az nehezebben vész el. Esetleg használhatjuk a perldoc formátumot, amit a perldoc paranccsal nézhetünk meg, és perlman, illetve perlhtml paranccsal generálhatunk belõle más formátumokat.
    • Érdemes megnézni a Getopt::Long modulban a GetOptions függvény használatát. A parancssori argumentumok feldolgozása ezzel nagyon egyszerû.
    • setuid programok írásánál hasznos lehet a -T parancssori paraméter amivel a taint üzemmódot kapcsolhatjuk be. Ezzel követni lehet az összes változó életét. A veszélyes parancsok nem lesznek végrehajtva, ha azok külsõ forrásból származó információn alapulnak. Persze néha elkeserítõ bír lenni, hogy a 263 soros programunkban 214 sorban használunk "büdös" (taint) inputot.
    • Ha valamilyen bonyolultabb feladatba kezdünk (nagyobb mint 200 sor), akkor ellenõrizzük le nem írta-e meg valaki azt a dolgot. (Én már láttam 400 soros HTTP szervert Perl-ben, ami cgi-bin programokat is kezelt!)

    • Pl.: ftp://ftp.kfki.hu/pub/packages/perl/CPAN/CPAN.html

    • Érdemes mindent mindjárt kipróbálni fejlesztés közben, mert elég gyors a rendszer ahhoz, hogy több ezer soros program is másodpercek alatt elinduljon.
    Jó szórakozást!


    Ezt a dokumentumot Frohner Ákos írta.
    Kiegészítette Nagy Péter írása és saját tapasztalatai, és Larry Wall írásai alapján: Milus János.


    Ennek a dokumentumnak a lemásolása illetve terjesztése csak teljes egészében történhet, a szerzõt megjelölõ sorokkal együtt.


    *