Láthatóság
Perlben alapértelmezés szerint minden változó globális (pontosabban egyik
sem az de erről később, egyelőre tekintsük őket globálisnak), azaz mindenki
látja, és tud is rá hivatkozni, tudja módosítani. Ez programozási szempontból
se nem kényelmes, se nem biztonságos. Szerencsére Perlben van lehetőség
ezt megkerülni.
Az egyik lehetőség erre a local használata. Ennek az operátornak a segítségével
a változónkat lokálissá tehetjük, a legszűkebb bezáró blokkra, szubrutinra,
eval blokkra, vagy filera nézve. Ez úgy történik, hogy a globális változó
értéke lementődik egy temporális helyre, ahonnan a blokk elhagyása után
másolódik vissza az eredeti érték. Ebből kifolyólag ha a blokkot még nem
hagytuk el, csak kihívunk belőle, akkor a hívott eljárásban a lokális értéket
fogjuk látni. A blokkban pedig nem lesz elérhető a változó globális értéke.
#!/usr/bin/perl -w
# itt adunk értéket a $a változónak
$a = 'outer';
# itt hívjuk meg az értéket kiíró metódust
printa();
# majd egy külön blokkban felveszünk egy local $a változót
{
local $a = 'inner';
print "local: \$a=$a\n";
# és kiírjuk a $a értékét
printa();
}
# a blokkból kilépve ismét kiírjuk a $a értékét
printa();
# ez az eljárás nem vesz át paramétereket, hanem a globális $a változót írja ki
sub printa {
print "\$a=$a\n";
}
Ennek a programnak az eredménye a következő lesz:
$a=outer
local: $a=inner
$a=inner
$a=outer
Érezhetően ez nem az, amit igazán szeretnénk.
Ezzel szemben a my már sokkal közelebb van ahhoz, amit más programozási
nyelvekben megszokhattunk. Egy my-jal deklarált változó, legyen az skalár,
tömb vagy hash, csak az adott blokkban létezik, és a globális változókat
is elérhetjük a package nevének megadásával.
#!/usr/bin/perl -w
# itt adunk értéket a $a változónak
$a = 'outer';
# itt hívjuk meg az értéket kiíró metódust
printa();
# majd egy külön blokkban felveszünk egy my $a változót
{
my $a = 'inner';
# kiírjuk a lokális változót
print "my: \$a=$a\n";
# elérhetjük a külső változót is
print "main: \$a=$main::a\n";
# és kiírjuk a $a értékét
printa();
}
# a blokkból kilépve ismét kiírjuk a $a értékét
printa();
# ez az eljárás nem vesz át paramétereket, hanem a külső $a változót írja ki
sub printa {
print "\$a=$a\n";
}
Ennek a programnak az eredménye a következő lesz:
$a=outer
my: $a=inner
main: $a=outer
$a=outer
$a=outer
Ha egyszerre több változót is szeretnénk my kulcsszóval deklarálni, akkor
azt úgy tehetjük meg, ha zárójellel vesszük körül, és ezzel tömb környezetbe
helyezzük:
sub mysub {
my ($a, $b) = @_;
....
}
Itt most átvettünk két paramétert, deklaráltunk hozzájuk két lokálisan
létező változót, ami megszunik, mikor kilépünk a szubrutinból.
Input, Output
Fileműveletekhez a Perl filehandle-t használ, ami nem valódi Perl változó,
ezért ha hivatkozni akarunk rá, akkor az úgynevezett typeglob operátort
kell használnunk (*). Erre akkor van szükségünk, ha a filehandle-t át szeretnénk
adni, vagy el szeretnénk tárolni, vagy éppen csak át szeretnénk irányítani.
Egy file kezelése röviden a következő módon történhet:
# myfile nevű file megnyitása, és hibakezelés, ha nem sikerül
open(MYFILE, "myfile") or die "Can't open file: $!\n";
while ( $line = <MYFILE> ) { # sor olvasása a $line változóba
print "olvastam: $line"; # a sor kiírása a STDOUT-ra
}
close MYFILE;
Ha egyszerűen csak a file tartalmát ki szeretnénk listázni:
open(FILE, "kiirni.txt") or die "A file-t nem tudom megnyitni.\n";
while (<FILE>) {
print;
}
close(FILE);
Ha egy sorba szeretnénk kiíratni a file tartalmát:
open(FILE, "kiirni.txt") or die "A file-t nem tudom megnyitni.\n";
while (<FILE>) {
chomp;
print;
}
close(FILE);
A megnyitott fileokat a Perl automatikusan lezárja. Ennek ellenére azért
mindenképpen hasznos ha mi magunk is lezárjuk a filet, ezzel is jelezve,
hogy már nem kívánunk olvasni belőle.
Érdekes és hasznos, hogy a <> operátor lista környezetben nem egy
sort ad vissza, hanem minden sort beolvas a fileból, és sorok listáját
kapjuk, amit aztán nyugodtan eltehetünk egy tömb változóba. A következő
példa teljesen ekvivalens az előzővel, de itt a <> operátort lista környezetben
használjuk.
# myfile nevű file megnyitása, és hibakezelés, ha nem sikerül
open(MYFILE, "myfile") or die "Can't open file: $!\n";
print map "olvastam: $_", <MYFILE>;
close MYFILE;
Megformázott output a printf segítségével
Könnyebb a megjelenítendő szöveget formázni mint
a print-el. Két argumentuma van, az első a formázást vezérlő string
a második pedig a szövegstring vagy szövegstringek listája.
Adattípus ----->Jelentés
c ------------->Karakter
d ------------->Tízes számrendszerbeli szám
e ------------->Exponenciális lebegőpontos szám
f ------------->Fixpontos lebegőpontos szám
g ------------->Kompakt lebegőpontos szám
ld ------------->Hosszú decimális szám
lo ------------->Hosszú nyolcas számrendszerbeli szám
lu ------------->Hosszú előjel nélküli decimális szám
lx ------------->Hosszú tizenhatos számrendszerbeli szám
o ------------->Nyolcas számrendszerbeli szám
s ------------->string
u ------------->Előjel nélküli decimális szám
x ------------->Tizenhatos számrendszerbeli szám
X ------------->Tizenhatos számrendszerbeli szám
nagybetűkkel
A formázást vezérlő stringen belül mezőjelek
vannak, amelyek meghatározzák a megjelenítendő adatok típusát és a mezőméretet,
amelybe az adat kerüljön. A mezőjel % jel.
printf "%10s", "Hello"; #Kiírja a
"Hello" stringet
10-hosszú mezőbe jobbra rendezve, vagyis a string a 6. pozíción kezdődik.
printf"%10d", 1000 #Kiírja az 1000 számot 10-hosszú
mezőbe, jobbra rendezve.
$pi=3.14159; #Második argumentum
egy változó. Ennek eredménye 3.14 lesz
amelyet egy 5-hosszúságú mezőben jelenít meg, vagyis a
printf"%5.2f", $pi;
#szám eggyel jobbralesz léptetve.
printf "10%s %5d %5.2f\n", "Hello", 123, $pi #Több
string kiírása egyszerre
# myfile nevű file megnyitása írásra, és hibakezelés, ha nem sikerül
open(MYFILE, ">myfile") or die "Can't open file: $!\n";
print MYFILE "Ez belemegy a fileba.";
close MYFILE;
Fájl input, output
<"filenév" Olvasásra nyitja meg a fájlt
>"filenév" Outputra nyitja meg a fájlt
>>"filenév" Egy létező fájl végéhez ír adatot
+<"filenév" írás és olvasásra nyitottuk meg a fájlt
File nyitáskor fellépő hibák kezelése:
ž warn kiírja hibát STDERR-re de engedi tovább futni a programot
ž die kiírja hibát STDERR-re és leállítja a program futását.
open(FILE, "myfile") or warn "can't open file"\n;
open(FILE, "myfile") or die "can't open file"\n;
A warnt-t akkor érdemes használni ha lekezeltük a programunkban azt az esetet ha nem sikerül a fájlt megnyitni, vagyis a programnak két variációja van!
Azt is megtehetjük, hogy egyik hibakezelő függvényt sem használjuk, ilyenkor a Perl undef-et ad vissza.
Ha elhagyjuk a fenti példában az új sor karaktert, meg tudjuk nézni hová teszi a Perl a hibaüzenetet.
Vannak előre definiált filehandle-k: STDIN, STDOUT, STDERR. A typeglob operátor használatára példa a következő, amiben a STDOUT filehandle-t irányítjuk át egy fileba:
open(FILE, ">/tmp/a");
*STDOUT=*FILE;
print STDOUT "hello"; # ez már a fent nevezett fileba megy
A fileok kezelése megoldható ezekkel a handle-ekkel, de van objektum-orientált
interfész is, ami elrejti ezeket a handle-eket, és egy könnyen kezelhető,
rugalmas interfészt ad. Az egyik az IO::File, a másik a FileHandle osztály.
Ezek bemutatására most nincs idő, de ez előző 'olvastam' példa FileHandle-t
használó, szinte olvashatatlanul tömör változatát ínyenceknek leírom:
use FileHandle;
-r "myfile" ? print map "olvastam: $_", FileHandle->new("myfile")->getlines() :
die "Can't read file: $!\n";
Természetesen bináris file-ok kezelésére is van mód. Egy filehandle-re kell
meghívni a binmode függvényt, majd a read függvénnyel olvashatunk belőle,
megadott pufferrel, megadott számú byteot. Bináris file-ba a syswrite utasítással
írhatunk.
open(ORIG, "original");
open(COPY, ">copy");
binmode(ORIG);
binmode(COPY);
while (read(ORIG, $buffer, 1024)) {
syswrite(COPY, $buffer);
}
close(COPY);
close(ORIG);
Fájlvizsgálatok
Annak érdekében, hogy elkerüljük egy egész adatfájl felülírására, Perlben meg tudjuk nézni, hogy a fájlt,
amit ki szeretnénk nyitni létezik e már vagy sem. Ezen kívül több mint 20 fájlvizsgálati lehetőség van.
Most itt a leghasznosabbakat fogom felsőrolni.
Minden fájlvizsgálatot egy gondolatjelet követő betű ír le majd ezt a fájl neve követi.
Érthetően a betű a mutatja a fordítónak melyik vizsgálatot hajtson végre.
-e "myfile" #A myfile nevű fájl létezését ellenőrzi, visszatérési értéke igaz ha a fájl létezik, különben hamis.
$file = "myfile" #Egy fájl írható és/vagy olvasható e
if(-r/w $file){
open(FILE,"myfile");
}
$file = "perl.exe"; #Egy fájl végrehajtható e
if(-x $file){
print"Ez a file végrehajtható. \n";
}
Vizsgálat Eredmény
-r A fájl olvasható
-w A fájl írható
-x A fájl végrehajtható
-o A fájt a felhasználó birtokolja
-R A fájl valódi felhasználó által olvasható
-W A fájl valódi felhasználó által írható
-X A fájl valódi felhasználó által végrehajtható
-O A fájlt valódi felhasználó birtokolja
-e A fájl létezik
-z A fájl létezik, de a mérete 0
-s A fájl létezik, de a mérete NEM 0
-f A fájl sima fájl
-d A fájl egy könyvtár
-l A fájl egy symlink
-S A fájl egy foglalat
-p A fájl egy pipe
-b A fájl egy blokkspeciális fájl
-c A fájl egy karakterspeciális fájl
-u A fájl setuid
-g A fájl setgid
-k A fájlnak ragadós bitkészlete van
-t Isatty() a fájlkezelőre igaz
-T A fájl egy szövegfájl
-B A fájl egy bináris file
-M Módosítás ideje napokban
-A Hozzáférés ideje napokban
-C Az I-csomópont módosítás ideje napokban
Mivel a fájlvizsgálatokkal csak egy-egy információt tudunk meg az egyes fájlokról, néha jól jön a
"stat" függvény ami egy meghatározott fájlról az alábbi információval tér vissza:
- A fájlrendszer eszközeinek száma
- Az i-csomópont száma
- Fájlmód
- A fájl kapcsolatainak a száma
- A fájltulajdonos numerikus felhasználói azonosítója
- A fájltulajdonos numerikus csoportazonosítója
- Az eszközazonosító
- A fájl teljes mérete bájtokban
- Utolsó használat időpontja
- Utolsó módosítás időpontja
- Az i-csomópont változásának időpontja
- Megfelelő blokkméret a fájlrendszer I/O számára
- Aktuálisan lefoglalt blokkok száma
Egy példaprogram filekezelésre:
A program a kiirni.txt file-t nyitja meg, ami tartalmazza a Biblia könyveinek egy részét.
Ennek a tartalmát kiírja a képernyőre, majd a felhasználó kiegészítheti a listát annyi könyvvel, amennyivel akarja (0-val
is lehet).
Ezután újra kiírja a file aktuális tartalmát, majd megformázza kissé a szöveget: 1 Mozes helyett Mozes első konyve
kerül kiírásra, Ruth helyett pedig Ruth konyve. Majd kereshetünk is a könyvek közt, amelyik nevét megadjuk, arról kiírja,
hogy hanyadik könyve a Bibliának (feltéve, hogy szerepel már a listánkban).
print "\nA file jelenlegi tartalma:\n";
&kiir(); # meghívom a kiir függvényt, ami lejjebb található.
open(FILE, ">>kiirni.txt") or die "A file-t nem tudom megnyitni.\n";
# Írásra nyitom meg a file-t, pontosabban a végéhez ír hozzá.
# Ha nem tudja megnyitni, hibaüzenettel kilép
print "\nA Biblia kovetkezo konyveinek a neve(amennyit szeretne <enter>-rel elvalasztva)!";
$book = <STDIN>;
# standard bemenetről jön
while ($book !~"^\n") {
#Amíg nem üres sort üt be, addig megy a ciklus
print FILE $book;
# Beírjuk a file-ba a kapott stringet
$book = <STDIN>;
}
close(FILE);
print "\nMost a kovetkezo a file tartalma:\n";
&kiir();
print "\nSzebb formaban igy is irhato:\n";
open(FILE, "kiirni.txt") or die "A file-t nem tudom megnyitni.\n";
while (<FILE>) {
chomp;
# levágja a sorvége jelet a beolvasott stringről
&szepit($_);
# Meghívja a szepit függvényt a beolvasott stringgel
}
close(FILE);
$book = "Mate";
print "\nMelyik konyvet szeretne megkeresni?(1Mozes, 2Mozes...vagy Mozes, Samuel... )\n";
$book = <STDIN>;
$szamol=1;
$van = "0";
open(FILE, "kiirni.txt") or die "A file-t nem tudom megnyitni.\n";
while (<FILE>) {
if ($_ =~ /$book/) {
# illeszti a beolvasott mintát
print "A $szamol-dik konyv.\n";
$van = "1";
}
$szamol+=1;
}
if ($van = '1') { goto Cimke;}
#Ha volt találat, a Cimkére ugrik
print "Nincs ilyen konyv!\n";
#Ha nem volt...
Cimke:
close(FILE);
$book = <STDIN>;
sub kiir {
# A file tartalmának kiirása a képernyőre
open(FILE, "kiirni.txt") or die "A file-t nem tudom megnyitni.\n";
while (<FILE>) {
print;
}
close(FILE);
}
sub szepit {
# pl az "1Mozes" kijavítása "Mozes első konyve"-re
# "Ruth"-ot pedig "Ruth konyve"-vé alakitja
$szo = $_;
# Az átadott string
if ($szo=~/\d/) {
# ha illeszkedik rá szám, levágja, (biztos van rá egyszerűbb mód is):
$mi = chop($szo);
$vissza = undef;
while ($szo =~ /\d/) {
$vissza = $mi . $vissza ;
$mi = chop($szo);
}
# Hozzárakja a számot betűvel hátul:
if ($mi=~"1") {
$vissza = $vissza . " első";
}
if ($mi=~"2") {
$vissza = $vissza . " masodik";
}
if ($mi=~"3") {
$vissza = $vissza . " harmadik";
}
if ($mi=~"4") {
$vissza = $vissza . " negyedik";
}
if ($mi=~"5") {
$vissza = $vissza . " otodik";
}
}
else {
# Ha nem volt szám a string-ben, nem változtat rajta.
$vissza = $szo;
}
$visza = $vissza . " konyve\n";
#hozzáfuzzük, hogy "konyve"
print $vissza;
}
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-szeru" 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';
...
$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.
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;
-
chdir EXPR
-
A working directory beállítására ad lehetőséget. Ha paraméter nélkül
hívjuk a home directory az alapértelmezett.
-
chomp
-
Az alant lévő chop függvény egy biztonságosabb verziója: csak a
sorvége karaktert vágja le a kifejezés, lista vagy ezeknek hiányában a
$/ végéről.
-
chop
-
Levágja az utolsó 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
-
chr NUMBER
-
Visszaadja az adott ASCII kódú karaktert.
-
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. Régebben ez volt a módja egy Perl
program "fordításának", manapság már nem javasolják.
-
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)
-
eof FILEHANDLE
-
Igazat ad ha a következő olvasás a FILEHANDLE által azonosított fájlon
eof-al térne vissza. Paraméter nélkül az utolsó olvasás eof-státuszát
kapjuk.
-
eval BLOCK
-
A BLOCK futtatása az aktuális környezetben. A BLOCK egy string is lehet.
Figyelem: az eval {...}; forma egyszerű utasításnak számít, ezért
utána ki kell rakni a ';'-t!
-
exec LIST
-
Egy operációs rendszer parancsot hívhatunk meg vele. A Perl script futása
felfüggesztődik amíg a másik program nem terminál. A LIST elemei a futtatandó
program és a paraméterek.
-
exists EXPR
-
Megmondja, hogy létezik-e az asszociatív tömb egy eleme, pl.: if exists
$tomb{"eleme"} ...
-
exit EXPR
-
Azonnal kilép a programból az EXPR kifejezés értékével.
-
format
-
Deklarál egy nyomtatási képformátumot, amit a write függvény használ fel.
format Something =
Test: @<<<<<<<< @||||| @
$str, $%, '$' . int($num)
$str = "widget";
$num = $cost / $quantity;
$~ = 'Something';
write;
Ezen kívül még amit a formátumról érdemes tudni, kicsit bővebben:
A formátum a Perl által biztosított jelentéskészítő sablon. Ez a sablon egy állandó (oszlopok fejlécei, címkék, rögzített szöveg, stb.) és egy változó (az éppen kimutatandó adatok) részt (mezők) definiál.
Használata három részből áll: formátum definiálása, a kiírandó adatok betöltése a formátum mezőkbe, formátum behívása.
A formátum definíció bárhol előfordulhat a szövegben, mint egy szubrutin.
A mezősorok rögzített szövegeket és a változó szöveg számára mezőtartókat tartalmazhatnak; a rákövetkező sorban adhatjuk meg, mely értékeket kívánjuk megjeleníteni a mezőtartókban. A mezőtartókat @<<...<alakban adhatjuk meg, n széles mezőtartóhoz n-1 < jelet biztosítva.
Ez a forma balra igazított; a jobbra igazítást a @-ot követő > jelekkel biztosíthatjuk.
A formátumot a write (formátum_név) függvénnyel hívhatjuk be.
Numerikus mezőtartókat pl. @###.## alakban definiálhatunk; a tizedes pont opcionális.
Több soros mezőtartók jele @*, az ezután következő változóban tárolt szöveg így tartalmazhat \n újsor karaktert is.
Kitöltött mezőt például ^<<< alakban állíthatunk elő. Ezek lényege, hogy segítségükkel kitöltött bekezdéseket hozhatunk létre, alkalmas sorokba tördelve a szóhatárokon, ha szükséges, sorátvitellel.
A kitöltött mező értéke skaláris változó, melyet a mezőbe való betöltéskor a Perl megváltoztat: a változó értéke a mező kitöltése után az, ami megmaradt a betöltött szavak eltávolítása után. Így a követjező formátummal:
format formátum
^<<<<<<<<<<<<<<<<<<<
$változó
^<<<<<<<<<<<<<<<<<<<
$változó
^<<<<<<<<<<<<<<<<<<<
$változó
^<<<<<<<<<<<<<<<<<<<
$változó
^<<<<<<<<<<<<<<<<<<<
$változó
a $változóban tárolt szöveget 5 darab, 20 karakter hosszú sorba tördelve írathatjuk ki.
Arra az esetre, ha a megadott mezősorok nem lennének elegendők egy változóban tárolt szöveg kiírására, két egymást követő ~ (tilde) jelet írhatunk a meződefinícióba. Az ilyen sorokat a Perl automatikusan addig ismétli, míg az eredmény egy teljesen üres sor nem lesz; az üres sor elnyomódik. A sor megállásához természetesen az is szükséges, hogy ne legyen benne állandó szöveg, különben sohasem lesz üres.
A lap teteje formátum: a Perl lehetővé teszi oldalak formázását és a nyomtatón megjelenő oldalak számozását.
Ez utóbbit a Perlben előre definiált $% változó biztosítja.
A következő formátum-definíció megakadályozza például, hogy a címkék széttörjenek az oldalhatárokon megszámozza az oldalakat:
format CIMKE_TETEJE =
@< oldal
$%
Az alapértelmezett oldalhossz 60 sor, mely az összes Perlben lévő alapértelmezéshez hasonlóan a select(fájlkezelő) utasítással az STDOUT helyett másik fájlkezelőt választunk ki.
-
getc FILEHANDLE
-
Egy bájtot olvas a FILEHANDLE által specifikált fájlból. Ha paraméter nélkül
hívjuk akkor az STDIN-ről teszi ugyanezt.
-
glob EXPR
-
EXPR file-név teljesen kiterjesztve. Úgy működik, mint a shell-ek file-név
kiterjesztő algoritmusa:foreach $file (glob "*.pl") {...}
-
index STR , SUBSTR [, POSITION]
-
SUBSTR előfordulását keresi STR-ben POSITION helyen kezdve.
-
join EXPR, LIST
-
A LIST által felsőrolt stringeket összekapcsolja egy stringgé az EXPR szeparátort
felhasználva.
-
keys ASSOC_ARRAY
-
ASSOC_ARRAY kulcsait adja vissza egy tömbben.
-
last
-
A C-beli break-hez hasonló, kilép az aktuális ciklusból. A program
a ciklus utáni utasításon folytatódik. A continue blokk nem hajtódik
végre. Ha egy cimkét írunk mögé a cimkére ugrik vissza.
$i = 7;
CIKLUS: while (1) {
$j = 1;
while (1) {
last if $j == 3 && $i < 9;
last CIKLUS if $j == 3;
print $i, $j++, ":";
}
$i++;
}
és az eredmény: 71:72:81:82:91:92
-
local EXPR
-
EXPR-ben felsőrolt 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) = @_;
chomp $szoveg1;
chomp $szoveg2;
print $szoveg1, ':', $szoveg2, '\n\n';
}
-
next
-
A C-beli continue szinonímája: a következő iterációra lép egy ciklusban.
-
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"); # csak olvasás
open(KI, ">/tmp/output"); # csak í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" kií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.
-
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.
# 11111
# 012345678901234
# | | | |
$s = 'bbb abbbabb bbb';
while ($s =~ m/bb/g) {
print pos($s), "\n";
}
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
14
15
-
pop ARRAY
-
Kiveszi egy tömb utiolsó elemét és visszatérési értékként adja.
-
push ARRAY,LIST
-
Az ARRAY tömböt, mint egy vermet kezeli, és a LIST lista elemeit hozzáfuzi
a tömb végéhez. Ennek megfelelően növekszik a tömb mérete. A visszatérési
érték a tömb új mérete. Ugyanaz mint a
for $value (@LIST) {
$ARRAY[++$#ARRAY] = $value;
}
utasítás, csak hatékonyabb.
-
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ő!
-
reset EXPR
-
Törli az összes változót, amelynek neve az EXPR-re (?PATTERN?) módon illeszkedik.
reset 'a-z'; # Törli az összes kisbetűs változót
reset 'A-Z'; # Ezzel vigyázzunk mert az ARGV, INC, ENV
# és SIG tömbjeink is áldozatul esnek neki
-
return
-
Alprogramból érték visszaadása. Ha ez nem szerepel, akkor az alprogram
utolsó utasításának értéke lesz visszaadva.
-
ref EXPR
-
Visszatérési értéke TRUE, ha az EXPR egy referencia é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,
ARRAY, HASH, CODE, GLOB. Ha a hivatkozott
objektum egy osztályhoz tartozik ,akkor az osztály nevét adja meg. A ref
hasonló a C-beli a typeof operátorhoz.
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";
}
-
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.
-
sleep EXPR
-
A script nyugovóra tér az EXPR-ben megadott másodpercre.
-
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.
-
splice ARRAY,OFFSET
-
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)
-
sprintf FORMAT, LIST
-
A printf-ben megszokottak szerint illeszti be a FORMAT-ban megadott stringbe
a LIST változóinak értékét.
-
stat EXPR
-
Egy 13 elemu 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.) 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
-
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 felsőrolt 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.
Alprogramok
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-szeru" 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';
...
$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(PROTO); # u.a. de prototípussal
sub NEV BLOCK # deklarálás és definíció
sub NEV(PROTO) BLOCK # u.a. prototípussal
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. A visszatérési
érték az alprogram utolsónak kiértékelt kifejezésének értéke lesz, hacsak
nincs egy
return utasításban más megadva.
sub max {
my $max = pop(@_);
foreach $elem (@_) {
$max = $elem if $max < $elem;
}
$max;
}
Az alprogram deklarálásakor megadhatunk prototípust is. A prototípus nem
más, mint a
$,
@, és
%
karakterek sorozata, ami megmondja, milyen típusú paramétereket vár a függvény.
A
@ és a
% karakterek csak a sorozat végén
szerepelhetnek, mert tömb (ill. hash) átvétele az összes fennmaradó paramétert
lenyeli, tehát az utána felsőrolt változók sohasem kapnának értéket.
sub max($$) {
...
}
$c = max($a, $b); # ez jó
@l = ($a, $b);
$c = max(@l); # itt hibát kapunk
$c = &max(@l); # így viszont lehet
A prototípust ritkán adjuk meg, mert nagyon sokszor kényelmes egy két skalárt
váró függvényt egy kételemu listával hívni (mint az előbb próbáltuk). A
prototípus ellenőrzése kikerülhető, ha a függvényt & karakterrel vagy
indirekt módon (pl. referencián keresztül) hívjuk.
Lokális változók alprogramokban:
Két utasítás létezik lokális változók definiálására:
-
A my utasítás, mely olyan változókat definiál, amik csak az alprogramon
belül léteznek.
-
A local utasítás, mely olyan változókat definiál, amik a főprogramban
nem, de az alprogramon belül és bármely az alprogram által meghívott alprogram
belsejében léteznek.
Amikor az alprogram véget ér, lokális változói megsemmisülnek; ha ismét
meghívásra kerül, a lokális változókból új másolatok definiálódnak.
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;
Paraméterátadás:
Érték szerint:
Alprogramoknak értékeket adhatunk át, melyeket argumentumoknak nevezünk.
Ezek száma tetszőleges lehet, de közülük csak egy lehet lista, mert az
értékek egy egyszerű listába kerülnek. Ha listát adunk át, akkor annak
az utolsó argumentumnak kell lennie.
sub ketlista{
my (@lista1, @lista2) = @_; # lista2 mindig ures
} # @_ elemei lista1-be kerulnek
Az argumentumok egy listája konvertálódnak, mely egy speciális rendszerváltozónak,
a @_-nak adódik értékül. Minden egyes alprogram argumentum-listájához létezik
a @_-ból egy példány (a @_ egy lokális változó).
Név szerint:
Alprogramnak egy tömbváltozót név szerint is átadhatunk definiálva a változónévhez
egy álnevet (
alias).
&my_sub{
my (@subarray) = @_;
$arraylength = @subarray;
}
A
my_sub meghívásakor
@array változóban tárolt lista
a @_ változóba másolódik. A másolás nagy méretu tömbök esetén időigényes
lehet.
&my_sub{
my (*subarray) = @_;
$arraylength = @subarray;
}
A
*subarray definíció mondja meg a Perl interpreternek, hogy az
a
my_sub-nak átadott aktuális listával dolgozzon ahelyett, hogy
másolatot készítene.
Ezt az alprogramot a @ helyett a *-gal kezdődő tömbváltozónévvel hívjuk
meg:
@myarray = (1, 2, 3, 4, 5);
&my_sub(*myarray);
Az alprogram végrehajtása alatt a
@subarray név azonos a
@myarray
névvel.
Ügyeljünk arra, hogy a
my_sub-ban a
@subarray tartalmának
változtatásakor a
@myarray tartalma is változik.
Cím szerint:
A C-hez hasonlóan ekkor az átadott érték valamely objektumnak a címe, nem
pedig az értéke. A
referencia felhasználásával indirekt
módon tudjuk az objektum értékét megváltoztatni.
Példa:
#!/usr/bin/perl
@var1 = 1;
@var2 = 2;
sub my_sub{
my ($a, $b) = @_;
$$a++;
$$b++;
}
&my_sub2(\$var1, \$var2);
print ("\$var1=$var1 \$var2=$var2\n");
#Az output: $var1=2 $var2=3
Predefiniált alprogramok:
A Perl definiál három speciális alprogramot, melyek speciális időben kerülnek
végrehajtásra.
-
A BEGIN alprogram mindig végrehajtódik a program elindulása előtt.
-
Az END alprogram mindig végrehajtódik a program terminálásakor (még die
esetén is).
-
Az AUTOLOAD alprogram végrehajtódik, ha a program nem létező alprogramot
próbál meghívni.
Névtelen alprogram létrehozása:
$alpref = sub BLOCK; # deklarálás
&$alpref(1, 2, 3); # hívás
Ez a technika főleg egyszer használatos alprogramoknál lehet hasznos, például
egy signal kezelő átdefiniálásakor.
Névtelen alprogramok definiált környezete
A névtelen alprogramokra jellemző, hogy mindig abban a környezetben futnak,
amelyben definiálták őket, még akkor is, amikor az adott környezeten kívülről
kerülnek meghívásra. Ez egy érdekes módja lehet a paraméterátadásnak, és
callback jellegu kódrészeket lehet vele írni.
sub newprint {
my $x = shift;
return sub { my $y = shift; print "$x, $y!\n"; };
}
$h = newprint("Hello");
$g = newprint("Üdvözlet");
# Valamivel később...
$h("világ!");
$g("mindenkinek");
És az eredmény:
Hello, világ!
Üdvözlet, mindenkinek!
Beépített függvények átlapolása
Sok beépített függvény átlapolható, de ezt csak akkor érdemes kipróbálni,
ha jó okunk van rá. Ilyen eset lehet a nem Unix-rendszereken a környezet
emulálása. Az átlapolás a
subs pragma segítségével történhet,
például így:
use subs 'chdir'; # az átlapolandó beépített függvények
chdir $valahova; # az új chdir használata
sub chdir { ... } # a chdir megvalósítása
Kiértékelési környezetek
Minden utasítás, operátor kiértékelése Perlben egy bizonyos környezetben
(kontextusban) hajtódik végre. Ezek két fő fajtája a skalár és a lista
környezet. Attól függően, hogy épp melyikben vagyunk, a kifejezések különbözőképpen
értékelődhetnek ki.
Például egy lista ha lista környezetben van, akkor visszaadja minden
elemét. Ha viszont skalár környezetben van, akkor a tömb elemszámát adja
vissza. Mi történik, ha a következőt írjuk le?
@empty;
unless (@empty) {
...
}
unless (()) {
...
}
@empty egy üres tömb, ennek az elemszáma 0, amiből '0' lesz, ami pedig
definíció szerint hamis. A második esetben azonban nem pontosan erről van
szó. Ha ugyanis nem változóban érjük el a listát, hanem a , operátorral
(illetve itt ()-val) hozzuk létre, akkor a lista skalár környezetben az
utolsó elemét adja vissza. Ez ennél az üres listánál történetesen undef-et
ad (ami nem azt jelenti, hogy undef az utolsó eleme, mert akkor már nem
lenne üres!), ami aztán ''-gé konvertálódik, ami pedig hamis lesz.
Néhány további rövid példa:
$val = ('a', 'b', 'c'); # $val == 'c'
@val = (@list1, @list2); # listák kiegyenesítése
@val = 3; # @val tartalmazni fogja a skalárt
($a, $b, $c) = @list; # szétosztja a lista elemeit a skalárok között,
# a maradékot pedig eldobja
A wantarray függvénnyel mi magunk is megtudhatjuk, hogy egy eljáráson belül
milyen környezetben vagyunk: lista-e vagy skalár. A következő példa ennek
felhasználására mutat egy példát (a példa alapja a perldoc -f wantarray
oldalon felhozott példa):
sub wantarray_test {
# ha void contextben vagyunk, akkor nincs értelme sokat dolgozni
return unless defined wantarray;
# valamilyen nagy műveletigényu számítás elvégzése
# ez le sem fut, ha void contextben vagyunk, azaz ha nem használnánk
# fel az eredményt
my @a = complex_calculation();
if ( wantarray ) {
# ha lista környezetben vagyunk, akkor adjuk vissza a listát
return @a;
}
else {
# skalár környezetben az elemeket :-val összefuzve adjuk vissza
return join(':', @a);
}
}
Lista környezetben erőltethetünk skalár környezetet a scalar kulcsszóval.
Például a következő példa a listák elemszámainak listáját állítja elő.
@counts = (scalar @list1, scalar @list2);
Ha itt kihagynánk a scalar kulcsszókat, akkor a listák lista környezetben
értékelődnének ki, és a tartalmukat adnák vissza, ami aztán kiegyenesítve
másolódna az @counts listába.
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).
$első = 1; # ez a $main::első
package MODUL; # uj modul kezdete
$masodik = 1; # $MODUL::masodik
$első = 1; # $MODUL::első
$main::első = 2; # $main::első
A főmodul neveihez még a
$::első hivatkozással is hozzáférhetünk.
Perlben kifejezhetjük, hogy nincs adott aktuális package. Ehhez adjuk
meg a
package utasítást packagenév nélkül.
package;
Ekkor az összes változó csak packagenév minősítéssel használható.
$MODUL::masodik = 21; # OK
$masodik = 21; # hiba - nincs aktuális package
E megszorítás érvényben marad addig, amíg nem definiálunk explicit egy
aktuális packaget egy másik
package utasítással.
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; }
Egy korábban importált modult a
no utasítással távolíthatunk el.
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.
Néhány predefinit modul
integer |
E modul mondja meg a Perlnek, hogy használjon egész aritmetikát lebegőpontos
aritmetika helyett. |
Diagnostics |
A Perl interpreter több figyelmeztető üzenetet ír ki a program futása
során. |
Env |
Egy Perl modul, ami környezeti változókat importál. |
POSIX |
A POSIX szabvány (IEEE 1003.1) Perlbeli interfésze. |
Socket |
Betölti a C nyelv socket kezelő mechanizmusait. |
Operátorok átlapolása
A Perl operátorainak nagyrésze átlapolható. Ehhez az overload pragma-t
kell használni. A korábbi verziókban még meglevő, de már ott sem támogatott
%OVERLOAD hash az 5.005-ös verziótól kezdve nem használható.
package Valami;
use overload
'+' => \&myadd,
'-' => \&mysub;
# stb.
...
package main;
$a = new Valami 57;
$b = $a + 5;
Az átlapolás figyelembe veszi az
@ISA hierarchiát, tehát minden
olyan osztályban érvényes lesz, ami
Valami-től örököl.
Az átlapolást megvalósító függvény 3 paramétert kap. Az első két paraméter
a bináris operátor két oldalán álló érték. Mivel a metódushívás általános
szabályai szerint az első paraméternek az adott osztályhoz tartozónak kell
lennie, ezért (pl. 7 + $a) esetén előfordulhat, hogy ezen szabály
betartásához az operandusokat meg kell cserélni, ami nem kommutatív műveletek
esetén nem egészséges. Ezért a fordító a 3. argumentumban jelzi, hogy felcserélte-e
az értékeket. Az unáris operátorokat a fordító úgy kezeli, mintha a 2.
argumentum undef lenne.
Az argumentumok referenciaként kerülnek átadásra, ezért lehetőség van
mellékhatások megvalósítására (mint pl. a ++ operátor esetén).
A következő operátorokat lehet átlapolni:
-
Aritmetikai operátorok: +, +=, -, -=, *, *=, /, /=, %, %=, **, **=, <<,
<<=, >>, >>=, x, x=, ., x=
-
Összehasonlító operátorok: <, <=, >, >=, ==, !=, <=>, lt, le,
gt, ge, ne, eq, cmp
-
Bit operátorok: &, ^, |, neg, ~, ! (neg: unáris -)
-
Növelés, csökkentés: ++, --
-
Matematikai funkciók: atan2, cos, sin, exp, abs, log, sqrt
-
Logikai, string és számkonverzió: bool, "", 0+
-
Speciális: nomethod, fallback, =
Elképzelhető, hogy a Perl nem találja az egyik operátorhoz rendelt metódust.
Ennek kezelésére szolgál a
"nomethod" nevű speciális operátor. Ha
definiálva van, akkor ez hívódik meg; első három paraméterként megkapja
a hiányzó művelet paramétereit, 4. paraméterként pedig a hiányzó művelet
nevét.
Ha egy művelet nincs definiálva, a "fallback" nevű speciális
operátor értéke dönti el a továbbiakat:
-
definiálatlan
-
Ekkor a Perl először elindítja a MAGIC AUTOGENERATION nevű eljárást, mely
egy függvényt próbál generálni az adott operátorhoz. Ha ez nem megy, akkor
a felhasználó által definiált "nomethod"-ot hívja. Ha ez sem működik, akkor
exception lép fel.
-
TRUE
-
Minden az előző esetnek megfelelően zajlik, csak exception nem lép fel,
hanem minden úgy folytatódik, mintha nem is lett volna átlapolás.
-
FALSE
-
A definiálatlan esettől abban tér el, hogy az autogenerálást nem próbálja
meg.
Figyelem: a
"fallback" és az öröklés kapcsolata még (az 5.005-ös
verzióban) nem teljesen tisztázott, később változhat.
Az "=" speciális operátorra a következő esetben van szükség:
$a = $b; # két referencia, ami ugyanoda mutat
$a++;
Ahhoz, hogy
$b értéke ne változzon a művelet hatására, az
$a
változóról egy másolatot kell készíteni - ezt végzi el az
"=" operátor,
ha definiálva van.