Perl alapjai VIII. - Könyvtárműveletek
Előző cikkünkben a Perl fájlkezelési lehetőségeivel ismerkedtünk meg, most ezt az irányt folytatva a Perl könyvtárkezelési képességeit tekintjük át, ezen belül is a könyvtárak tartalmának listázását, a könyvtárak manipulálását, s pár további lehetőséget, melyeket külső modulok segítségével érhetünk el. A cikk keretében pár hasznos trükkre is ki fogunk térni, melyek lehetővé teszik, hogy hatékonyan kezeljük könyvtárainkat.
A könyvtárak kezelése sokszor jöhet jól, akár a bemeneti adatok felderítése kapcsán, akár más feladatok esetén. A könytárak közötti váltás, egy könyvtár létrehozása, törlése az alapfeladatok közé tartozik, de nem mondható bonyolultnak egy könyvtár tartalmának meghatározása sem. Ezekre a Perl beépített függvényeket biztosít. Sokszor lehet azonban hasznos egy teljes rekurzív könyvtárszerkezet felderítése, vagy két könyvtár szinkronizálása, ezekre és sokminden másra különböző modulok állnak rendelkezésünkre.Könyvtárak közötti váltás:
A könyvtárak közötti váltás a
AKönyvtár létrehozása:
Könyvtár létrehozására az
AKönyvtár törlése:
Egy könyvtárat az
A
Egy könyvtár megnyitására aA megnyitott könyvtárat ezentúl a megadott azonosítóval érhetjük el (a példában
A könyvtárból egy fájl kiolvasására a
A visszaadott sztring csak és kizárólag a fájl nevét fogja tartalmazni, az útvonalát nem. Erre akkor kell figyelnünk, ha a megnyitott könyvtár nem az aktuális, s a fájlokkal szeretnénk kezdeni valamit: az útvonalat a kapott fájlnevek elé kell írnunk, hogy hozzáférhessünk azokhoz.
Jó tudni, hogy általában az operációs rendszerek alatt egy könyvtárnak nem csak a benne található könyvtárak és fájlok a részei, tartalmának lekérdezésekor egy magára a könyvtárra mutató fájlnevet (
Egy könyvtárt bezárni a
A könyvtárkezelés kapcsán három további függvény is rendelkezésünkre áll, melyek a könyvtáron belüli pozícionálással foglalkoznak, vagyis a megnyitott könyvtárban levő éppen aktuális pozíciót (hányadik fájlnál járunk) olvashatjuk ki, vagy módosíthatjuk segítségükkel.
A
A
A könyvtárkezeléssel kapcsolatosan van pár trükk, melyet ha ismerünk, hatékonyabban végezhetjük el feladatainkat. A következőkben pár ilyet tekintünk át.Természetesen az útvonal akkor lesz csak teljes, ha a megadott könyvtár paraméter is teljes útvonalat tartalmazott. Fontos, hogy a könyvtár nevének megadásakor a végén szerepeljen egy perjel, hogy amikor összefűzzük a könyvtárat és a fájlnevet, stimmeljen a végeredmény.
A trükk a függvény közepén látható: aA szűrésre az arra kiválóan alkalmas Mivel a fájlnév már teljes útvonalat fog tartalmazni, ezért a
Ha például kiterjesztés szerint szeretnénk szűrni, aTalán azt érdemes ennek kapcsán megemlíteni, hogy mivel a mintaillesztő kifejezést is a Bár az egész
A
AAz első sorban jeleztük, hogy a modul szolgáltatásait használni szeretnénk. A második sorban meghívtuk a
A megadott függvényben három "speciális" változó áll rendelkezésünkre. A
Harmadik és további paraméterként további könyvtárakat is felsorolhatunk.
Az első paraméter lehet egy hash is, mely használat esetén szabályozhatjuk a függvény működését különböző kérdésekben. Lássunk erre is egy példát:A futtatandó függvényt továbbra is be kell állítanunk, erre a
A modul több további lehetőséget is kínál, ezek megismeréséhez a dokumentációja jó kiindulópont lehet.
Egy példa a használatára:Ez a kis program a megadott könyvtárakat fogja egymással szinkronizálni. Fájlokat és könyvtárakat másol vagy töröl, időbélyegeket állít be, szimlinkeket hoz létre vagy távolít el. A forrás könyvtár állapotát átmeneti tárban rögzíteni tudja, ezzel még hatékonyabbá téve a szinkronizációt.
Paraméterek segítségével szabályozhatjuk a részletességet, az átmeneti tár használatát, hogy csak helyi, vagy "felmountolt" fájlokat is vizsgáljon-e. Akár egyesével is másoltathatunk, megadhatunk kihagyandó fájlokat, könyvtárakat (pl. "CVS"), s lekérdezhetjük a legutóbbi szinkronizáció során történteket (mely fájlok kerültek frissítésre, eltávolításra, lettek figyelmen kívül hagyva, illetve melyek esetén jelentkezett valamely hiba). Egy külön parancs segítségével az átmeneti tárat felépíthetjük, azaz a szinkronizációs adatbázist még a szinkronizáció előtt elkészíthetjük, ezáltal is javítva annak hatékonyságát.
A modulról további információkat a dokumentációjában találhatuk.
■ A sorozatban megjelent
- Perl alapjai I. - A múlt és a jövő
- Perl alapjai II. - Fejlesztői környezet, alapok
- Perl alapjai III. - Műveletek
- Perl alapjai IV. - Tömbök, hashek, elágazások, ciklusok és szubrutinok
- Perl alapjai V. - Mintaillesztő kifejezések
- Perl alapjai VI. - Fájlkezelés
- Perl alapjai VII.- Fájlműveletek
- Perl alapjai VIII. - Könyvtárműveletek
- Perl alapjai IX. - Adatbáziskezelés
Könyvtárak közötti váltás: chdir
A könyvtárak közötti váltás a chdir
paranccsal lehetséges. Egyetlen opcionális paramétere van: azt kell megadni, hogy mely könyvtár legyen ezentúl az aktuális. Ha ezt a paramétert elhagyjuk, akkor az alapértelmezett (home) könyvtárra fog ugrani, melyet a HOME
környezeti változóból próbál meg kideríteni. Ha ez nincs beállítva, akkor a LOGDIR
környezeti változót ellenőrzi le. Amennyiben nem adunk meg paramétert, s ezek egyike sincs beállítva, nem fog történni semmi sem.A
chdir
parancs visszatérési értéke igaz, ha a váltás sikeres, hamis, ha a váltás sikertelen.
chdir "/home/boogie/teszt";
Könyvtár létrehozása: mkdir
Könyvtár létrehozására az mkdir
parancs szolgál. Egy vagy két paramétert adhatunk meg, az első, kötelező paraméter az új könyvtár neve (ha csak egy nevet adunk meg, akkor az aktuális könyvtárban lesz létrehozva, de megadhatunk relatív és abszolút útvonalakat is) kell, hogy legyen, a második, opcionális paraméter pedig a létrehozandó könyvtár hozzáférési maszkja. Amennyiben ezt elhagyjuk az alapértelmezett érték 0777
. A maszk megadásakor ne feledjük, hogy nyolcas számrendszerben kell érteni, azaz a szám elé tegyünk egy 0
-t is, hogy nyolcas számrendszerbelinek értelmezze a Perl (persze leírhatjuk a 0666
helyett azt is, hogy 438
, ami a decimális megfelelője, de ettől inkább csak olvashatatlanabb kódot kapunk).A
mkdir
parancs visszatérési értéke igaz, ha a könyvtár sikeresen létrejött, míg hamis, ha nem. Ez utóbbi esetben a $!
változó is beállításra kerül, mely a hibakódot fogja tartalmazni (vagy ha sztring környezetben olvassuk ki, akkor a hiba nevét).
mkdir "/home/boogie/teszt";
Könyvtár törlése: rmdir
Egy könyvtárat az rmdir
parancs segítségével törölhetünk. Egy opcionális paramétert vár, a törlendő könyvtár nevét. Ha ezt nem adjuk meg, akkor a $_
változóban levő könyvtárat törli. A könyvtárat csak akkor tudja törölni, ha az üres. Ha rekurzív könyvtártörlést szeretnénk, vagy magunknak kell azt megírnunk, vagy pedig használhatjuk például az operációs rendszer által biztosított parancsot is erre a feladatra.A
rmdir
parancs visszatérési értéke igaz, ha sikerült törölni a könyvtárat, hamis, ha nem. Ekkor beállításra kerül a $!
változó, értéke a hibakód, illetve sztring környezet esetén a hiba neve lesz.
rmdir "/home/boogie/teszt";
Könyvtárak listázása
A könyvtárak listázása egy fájl megnyitásához hasonlóan történik: alapvetően egy könyvtár megnyitás, olvasás és lezárás parancs áll rendelkezésünkre ehhez a feladathoz (és még további hárommal is megismerkedünk mindjárt). A könyvtár olvasása közben a benne levő fájlokat kapjuk vissza.Egy könyvtár megnyitására a
opendir
parancs szolgál. A fájlkezelés kapcsán megismert open
parancshoz nagyon hasonló: egy azonosítót kell megadni, majd a megnyitni kívánt könyvtárat. Például:
opendir DIR, "/home/boogie/teszt";
DIR
, de természetesen adhatunk neki bármely más nevet is). A könyvtár nevének végén nem kötelező /
(UNIX/Linux) vagy \
(Windows) karaktereket megadni, saját ízlésünktől függ, hogy teszünk-e ilyet oda, vagy nem.A könyvtárból egy fájl kiolvasására a
readdir
parancsot használhatjuk. Egy paramétere van, a könyvtár azonosító. Egy sztringet ad vissza, mely az adott könyvtárban levő következő fájl neve, ha skalár környezetben hívjuk meg. Ha a környezet listát vár, akkor az összes könyvtárban levő fájlt adja vissza (ha már olvastunk ki fájlokat, akkor az összes többit).A visszaadott sztring csak és kizárólag a fájl nevét fogja tartalmazni, az útvonalát nem. Erre akkor kell figyelnünk, ha a megnyitott könyvtár nem az aktuális, s a fájlokkal szeretnénk kezdeni valamit: az útvonalat a kapott fájlnevek elé kell írnunk, hogy hozzáférhessünk azokhoz.
Jó tudni, hogy általában az operációs rendszerek alatt egy könyvtárnak nem csak a benne található könyvtárak és fájlok a részei, tartalmának lekérdezésekor egy magára a könyvtárra mutató fájlnevet (
.
) és egy a könyvtár szülőjére mutató fájlnevet (..
) is visszakaphatunk (visszakapunk).Egy könyvtárt bezárni a
closedir
paranccsal tudunk, mely felszabadítja az azonosítót és a hozzárendelt memóriaterületet. Ha a könyvtárat nem zárjuk be, akkor nem kapunk hibaüzenetet, a programunk végén ez automatikusan meg fog történni. Ha sok könyvtárral dolgozunk, a memóriafoglalás és a rend miatt érdemes egyedül lezárni a könyvtárakat.A könyvtárkezelés kapcsán három további függvény is rendelkezésünkre áll, melyek a könyvtáron belüli pozícionálással foglalkoznak, vagyis a megnyitott könyvtárban levő éppen aktuális pozíciót (hányadik fájlnál járunk) olvashatjuk ki, vagy módosíthatjuk segítségükkel.
A
rewinddir
működése elég egyszerű, nem tesz mást, mint a könyvtár elejére ugrik, vagyis a helyzet ugyanaz lesz, mintha épp most nyitottuk volna meg a könyvtárat. Egy paramétere van, a könyvtárazonosító, melyhez az opendir
paranccsal jutottunk hozzá.A
telldir
segítségével azt tudhatjuk meg, hogy hányadik fájlnál járunk, egy paramétere van, a könyvtárazonosító. A seekdir
ennek pont az ellenkezőjét teszi: valamely pozícióra ugrik. Az első paramétere a könyvtárazonosító, a második pedig a pozíció. A könyvtárkezeléssel kapcsolatosan van pár trükk, melyet ha ismerünk, hatékonyabban végezhetjük el feladatainkat. A következőkben pár ilyet tekintünk át.
Abszolút fájlnevek
Az előbbiekben szó volt róla, hogy areaddir
parancs csak és kizárólag a fájlnevet adja vissza. A következő függvény segítségével egy könyvtár tartalmát kaphatjuk vissza, teljes útvonalakkal:
sub listdir {
my($dir)=@_;
my(@files);
opendir(DIR, $dir);
@files=map($dir.$_,readdir(DIR));
closedir(DIR);
return(@files);
}
A trükk a függvény közepén látható: a
map
függvényt használtuk fel ahhoz, hogy a visszakapott fájlnevek mindegyikéhez hozzáfűzzük a könyvtárat is. Ahogy a korábbiakban már volt szó róla, lista környezetben a readdir
nem egy fájlt, hanem az összeset fogja visszaadni, ezt használtuk ki ebben az esetben.Csak fájlok, csak bizonyos fájlok
Elég gyakori feladat, hogy egy könyvtárban csak a fájlokra, vagy csak bizonyos tulajdonságú fájlokra vagyunk kíváncsiak. A következő függvény megszűri a könyvtár tartalmát, s csak a fájlokat adja vissza belőle:
sub dirfiles {
my($dir)=@_;
my(@files);
opendir(DIR, $dir);
@files=grep(-f $dir.$_,readdir(DIR));
closedir(DIR);
return(@files);
}
grep
parancsot használjuk, feltételéül pedig a "fájl-e?" operátort. Jelen változat csak a fájlnevet adja vissza, a könyvtárat nem fűzi elé, ha ezt szeretnénk, még egy az előzőekben látott módon kivitelezett map
parancsot érdemes betenni a readdir
elé. Ekkor így alakul a függvény:
sub dirfiles {
my($dir)=@_;
my(@files);
opendir(DIR, $dir);
@files=grep(-f,map($dir.$_,readdir(DIR)));
closedir(DIR);
return(@files);
}
-f
operátornak nem kellett paramétert adnunk, az alapértelmezett $_
teljesen megfelel nekünk.Ha például kiterjesztés szerint szeretnénk szűrni, a
grep
feltételét egészíthetjük ki a legegyszerűbben egy mintaillesztő kifejezéssel. A következő példa a könyvtár .pl
kiterjesztésű fájlait adja vissza:
sub dirfiles {
my($dir)=@_;
my(@files);
opendir(DIR, $dir);
@files=grep(-f and /\.pl$/,map($dir.$_,readdir(DIR)));
closedir(DIR);
return(@files);
}
$_
-ra szeretnénk illeszteni, így ebben az esetben sem kellett megadnunk az illesztés tárgyát, ahogyan azt a -f
operátor esetén is elhagytuk.Rekurzív könyvtárszerkezet
Rekurzív könyvtárszerkezet összeállítására a cikk folyamán még látni fogunk egy nagyon jól használható (s a Perl disztribúciókban alapból telepített) modult, de nem árt, ha megismerjük, hogyan kell megoldani egy ilyen feladatot. A következő függvény ezt a feladatot valósítja meg:
sub recursivefiles {
my($dir)=@_;
my(@files);
opendir(DIR, $dir);
foreach(map($dir.$_,readdir(DIR))) {
if (-f) {
push @files,$_;
}
elsif (!/^\.\.?$/) {
push @files,recursivefiles("$_/");
}
}
closedir(DIR);
return(@files);
}
foreach
ciklus kiváltható lenne egy kifejezéssel, de az érthetőség miatt maradtam egy kicsit jobban kifejtett megoldásnál. Lássuk, mi mit csinál!A
foreach
már egy "teljes" útvonalalat tartalmazó fájlnév csokrot kap, melynek minden elemén végig fog menni. Az első if
egy egyszerű fájlvizsgálat, ha fájlról van szó, akkor a tömbbünkbe kerülhet a fájlnév. A második if
, esetünkben elsif
ágra akkor kerül sor, ha nem fájlról, azaz könyvtárról van szó. Ha ez a könyvtár nem .
, vagy ..
nevű, akkor szükségünk lesz a benne levő fájlokra, s ekkor ezen a ponton erre a könyvtárra meghívjuk a függvényt magát, majd a visszakapott fájllistát beletesszük a visszadandó listába.További lehetőségek
A következőkben pár Perl modult tekintünk át, melyek valamilyen módon a könyvtárkezeléshez kapcsolódnak. További modulokat a search.cpan.org címen kereshetünk.File::Find
A File::Find egy elsőre egyszerűnek tűnő, de elég rugalmas modul rekurzív könyvtárszerkezetek kezelésére. Két új függvényt biztosít, afind
és finddepth
függvényeket. Az utóbbi az első egy speciális változata.A
find
parancs alapvetően a paraméteréül kapott könyvtárakat nézi végig, s minden fájlra, amit talál, meghív egy (paraméterként megadott) függvényt. Íme egy példa:
use File::Find;
find(\&wanted, ".");
sub wanted {
print "$_\n";
}
find
parancsot, úgy, hogy a jelenlegi könyvtár (.
) tartalmán menjen végig rekurzívan, s minden talált fájl esetén futtassa le a wanted
függvényt. A függvényben ezután kiíratjuk az aktuális fájlnevet.A megadott függvényben három "speciális" változó áll rendelkezésünkre. A
$_
alapértelmezett esetben az aktuális fájlnevet tartalmazza, könyvtár nélkül. A fenti példában látható $File::Find::name
a fájlnévben a könyvtárnevet is szerepelteti, a $File::Find::dir
pedig csak az aktuális könyvtárat tartalmazza. Ezeket a változókat ne módosítsuk!Harmadik és további paraméterként további könyvtárakat is felsorolhatunk.
Az első paraméter lehet egy hash is, mely használat esetén szabályozhatjuk a függvény működését különböző kérdésekben. Lássunk erre is egy példát:
use File::Find;
find({ wanted=>\&wanted, no_chdir=>1 }, ".");
sub wanted {
print "$_\n";
}
wanted
kulcsszóval van lehetőségünk. A no_chdir
a könyvtárakba lépkedést szabályozza, ebben az esetben kapcsolja ki. A find
függvény alapértelmezett esetben a chdir
parancs segítségével könyvtárat vált, s belép az éppen megtalált könyvtárba. Ennek kapcsán helyben különböző műveleteket tudunk elvégezni, anélkül, hogy az útvonallal törődnünk kellene. Ha ezt a viselkedést ki szeretnénk kapcsolni, használhatjuk a no_chdir
paramétert. Beállításával egy másik változás is életbe lép, a $_
értéke ezúttal a könyvtárat is tartalmazni fogja.A modul több további lehetőséget is kínál, ezek megismeréséhez a dokumentációja jó kiindulópont lehet.
File::DirSync
A File::DirSync modul segítségével két könyvtár tartalmát szinkronizálhatjuk, azaz érhetjük el, hogy ugyanaz legyen a tartalmuk. A cél a leghatékonyabb, legkevesebb művelettel, leggyorsabban végrehajtott szinkronizáció.Egy példa a használatára:
use File::DirSync;
my $dirsync = new File::DirSync {
verbose => 0,
nocache => 1,
localmode => 1,
src => "/home/boogie/teszt",
dst => "/www/barthazi.hu/teszt"
};
$dirsync->dirsync();
Paraméterek segítségével szabályozhatjuk a részletességet, az átmeneti tár használatát, hogy csak helyi, vagy "felmountolt" fájlokat is vizsgáljon-e. Akár egyesével is másoltathatunk, megadhatunk kihagyandó fájlokat, könyvtárakat (pl. "CVS"), s lekérdezhetjük a legutóbbi szinkronizáció során történteket (mely fájlok kerültek frissítésre, eltávolításra, lettek figyelmen kívül hagyva, illetve melyek esetén jelentkezett valamely hiba). Egy külön parancs segítségével az átmeneti tárat felépíthetjük, azaz a szinkronizációs adatbázist még a szinkronizáció előtt elkészíthetjük, ezáltal is javítva annak hatékonyságát.
A modulról további információkat a dokumentációjában találhatuk.
Összefoglalás
A jelenlegi alkalommal a könyvtárakkal kapcsolatos lehetőségeket tekintettük át, megismerkedtünk pár trükkel, s két modullal is. Ha utána szeretnénk nézni, milyen modulok állnak rendelkezésünkre, a search.cpan.org nyújthat ebben segítséget, aFile
és Dir
szavakra érdemes rákeresni. Legközelebb a tervek szerint a Perles adatbáziskezelés lehetőségeinek alapjait tekintjük át.