103.7 Lecke 1
Tanúsítvány: |
LPIC-1 |
---|---|
Verzió: |
5.0 |
Témakör: |
103 GNU és Unix parancsok |
Fejezet: |
103.7 Keresés szövegfájlokban reguláris kifejezések segítségével |
Lecke: |
1/2 |
Bevezetés
A sztring-kereső algoritmusokat számos adatfeldolgozási feladat széles körben használja, olyannyira, hogy a Unix-szerű operációs rendszereknek saját, mindenütt jelenlévő implementációjuk van: Reguláris kifejezések, (regular expressions) gyakran rövidítve REs. A reguláris kifejezések olyan karaktersorozatokból állnak, amelyek egy általános mintát alkotnak, amelyet egy nagyobb karaktersorozatban lévő megfelelő sorozat megkeresésére és néha módosítására használnak. A reguláris kifejezések nagymértékben kibővítik a következő lehetőségeket:
-
Elemzési szabályok írása HTTP-kiszolgálók, különösen az nginx kéréseihez.
-
Szkriptek írása, amelyek szöveges alapú adathalmazokat konvertálnak más formátumba.
-
Érdekes előfordulások keresése logokban vagy dokumentumokban.
-
Markup dokumentumok szűrése, a szemantikus tartalom megtartása.
A legegyszerűbb reguláris kifejezés legalább egy atom-ot tartalmaz. Az atom, amely azért kapta ezt a nevet, mert ez a reguláris kifejezés alapeleme, nem más, mint egy karakter, amelynek lehet speciális jelentése, de lehet, hogy nincs. A legtöbb közönséges karakter egyértelmű, megtartják szó szerinti jelentésüket, míg másoknak speciális jelentésük van:
.
(pont)-
Az atom illeszkedik bármely karakterre.
^
(caret)-
Az atom illeszkedik a sor elejével.
$
(dollárjel)-
Az atom illeszkedik a sor végével.
Például a bc
reguláris kifejezés, amely a b
és c
literális atomokból áll, megtalálható az abcd
karakterláncban, de nem található meg az a1cd
karakterláncban. Másrészt a .c
reguláris kifejezés megtalálható mind az abcd
, mind az a1cd
karakterláncban, mivel a .
pont bármely karakterrel megegyezik.
A caret és a dollárjel atomokat akkor használjuk, ha csak a karakterlánc elején vagy végén lévő találatok érdekesek. Emiatt anchors-nak (horgony) is nevezik őket. Például a cd
megtalálható az abcd
-ben, de a ^cd
nem. Hasonlóképpen, az ab
megtalálható az abcd
-ben, de az ab$
nem. A ^
caret szó szerinti karakter, kivéve, ha az elején áll, és a $
is szó szerinti karakter, kivéve, ha a reguláris kifejezés végén áll.
Zárójeles kifejezés
Létezik egy másik atomtípus is, amelynek neve bracket expression (zárójeles kifejezés). Bár nem egyetlen karakter, a zárójelek []
(tartalmukkal együtt) egyetlen atomnak tekinthetők. A zárójeles kifejezés általában csak egy lista szó szerinti karakterekből, amelyeket []
zár be, így az atom a lista bármelyik karakterével megegyezik. Például a [1b]
kifejezés megtalálható mind az abcd
, mind az a1cd
karakterláncban. Ha meg akarjuk adni, hogy az atom ne feleljen meg a karaktereknek, a listának ^
-vel kell kezdődnie, mint a [^1b]
-ben. Karaktertartományok megadása zárójeles kifejezésekben is lehetséges. Például a [0-9]
megfelel a 0-tól 9-ig terjedő számjegyeknek, az [a-z]
pedig bármely kisbetűs betűnek. A tartományokat óvatosan kell használni, mivel előfordulhat, hogy nem konzisztensek a különböző helyi tartományokban.
A zárójeles kifejezéslisták az egyes karakterek és tartományok helyett osztályokat is elfogadnak. A hagyományos karakterosztályok a következők:
[:alnum:]
-
Alfanumerikus karaktert reprezentál.
[:alpha:]
-
Alfabetikus karaktert reprezentál.
[:ascii:]
-
Az ASCII karakterkészletbe illeszkedő karaktert reprezentál.
[:blank:]
-
Egy üres karaktert, tabot vagy szóközt reprezentál.
[:cntrl:]
-
Egy control karaktert reprezentál.
[:digit:]
-
Egy számjegyet (0-9 között) reprezentál.
[:graph:]
-
Bármilyen nyomtatható karaktert (a szóköz kivételével) reprezentál.
[:lower:]
-
Egy kisbetűs karaktert reprezentál.
[:print:]
-
Bármilyen nyomtatható karaktert (beleértve a szóközt is) reprezentál.
[:punct:]
-
Bármilyen nyomtatható karaktert (kivéve a szóközt és az alfanumerikus karaktereket) reprezentál.
[:space:]
-
White-space karaktereket: space, form-feed (
\f
), newline (\n
), carriage return (\r
), horizontal tab (\t
), és vertical tab (\v
) karaktereket reprezentál. [:upper:]
-
Egy nagybetűs betűt reprezentál.
[:xdigit:]
-
Hexadecimális számokat (0 és F között) reprezentál.
A karakterosztályok egyedülálló karakterekkel és tartományokkal kombinálhatók, de nem használhatók tartomány végpontjaként. Továbbá a karakterosztályok csak zárójeles kifejezésekben használhatók, a zárójelen kívül önálló atomként nem.
Kvantorok
Egy atom elérést, akár egykarakteres atom, akár zárójeles, egy atom quantifier (atom kvantor) segítségével lehet beállítani. Az atom kvantorok atom szekvenciákat határoznak meg, vagyis akkor történik találat, ha az atomnak egy összefüggő ismétlődése található a karakterláncban. Az egyezésnek megfelelő részláncát darabnak nevezzük. Ettől függetlenül a kvantorokat és a reguláris kifejezések egyéb jellemzőit másképp kezelik attól függően, hogy melyik szabványt használják.
A POSIX által meghatározottak szerint a reguláris kifejezéseknek két formája létezik: “basic” (alap) és “extended” (kiterjesztett) reguláris kifejezések. A legtöbb szöveggel kapcsolatos program bármely hagyományos Linux-disztribúcióban mindkét formát támogatja, ezért fontos ismerni a különbségeket a kompatibilitási problémák elkerülése és a tervezett feladathoz legmegfelelőbb implementáció kiválasztása érdekében.
A *
kvantornak ugyanaz a funkciója az alap és a kiterjesztett REs-ben (az atom nulla vagy több alkalommal fordul elő), és szó szerinti karakter, ha a reguláris kifejezés elején jelenik meg, vagy ha a \
backslash előzi meg. A ` pluszjel kvantor olyan darabokat választ ki, amelyek egymás után egy vagy több atomot tartalmaznak. A kérdőjeles kvantorral `?` akkor lesz egyezés, ha a megfelelő atom egyszer jelenik meg, vagy ha egyáltalán nem jelenik meg. Ha egy `\` backslash előzi meg ezeket, akkor a speciális jelentésüket nem vesszük figyelembe. Az alapvető reguláris kifejezések támogatják a `
és ?
kvantorokat is, de ezeket is meg kell előznie a backslashnek. A kiterjesztett reguláris kifejezésektől eltérően a +
és a ?
önmagukban szó szerinti karakterek az alap reguláris kifejezésekben.
Korlátok
A bound (korlát) egy olyan kvantor, amely, mint a neve is mutatja, lehetővé teszi a felhasználó számára, hogy pontos mennyiségi korlátokat adjon meg egy atomhoz. A kiterjesztett reguláris kifejezésekben a bound háromféle formában jelenhet meg:
{i}
-
Az atomnak pontosan
i
-szer kell megjelennie (i
egy egész szám). Például a\[{2}
pontosan két üres karakterrel egyezik. {i,}
-
Az atomnak legalább
i
-szer kell megjelennie (i
egy egész szám). Például a\[{2,}
bármely két vagy több üres karakterből álló sorozattal megegyezik. {i,j}
-
Az atomnak legalább
i
-szer és legfeljebbj
-szer kell megjelennie (i
ésj
egész számok,j
nagyobb, minti
). Például azxyz{2,4}
azxy
karakterláncot követi kettő-négyz
karakter.
Bármilyen esetben, amikor egy substring megfelel egy reguláris kifejezésnek, és egy hosszabb, ugyanott kezdődő substring is megfelel, akkor a hosszabb substringet vesszük figyelembe.
Az alap reguláris kifejezések is támogatják a kolrátokat, de a delimiterek előtt \
-nek kell állnia: \{
és \}
. A {
és }
önmagukban szó szerinti karakterekként értelmezhetők. A \{
, amelyet egy számjegyen kívüli szó szerinti karakter követ, nem pedig egy korlát kezdőbetűje.
Branchek és visszautalások
Az alap reguláris kifejezések egy másik fontos szempontban is különböznek a kiterjesztett reguláris kifejezésektől: egy kiterjesztett reguláris kifejezés ágakra (branchekre) osztható, amelyek mindegyike egy-egy független reguláris kifejezés. Az ágak |
-vel vannak elválasztva, és a kombinált reguláris kifejezés minden olyan kifejezésre illik, amely megfelel bármelyik ágnak. Például a he|him
akkor talál, ha a vizsgált karakterláncban megtalálható a he
vagy a him
részlánc. Az alapvető reguláris kifejezések a |
karaktert szó szerinti karakterként értelmezik. A legtöbb program azonban, amely támogatja az alapvető reguláris kifejezéseket, engedélyezi a \|
ágakat.
A kiterjesztett reguláris kifejezést ()
-be zártan lehet használni egy visszautalásban (back reference). Például a ([[:digit:]])\1
minden olyan reguláris kifejezésre illik, amely legalább egyszer megismétli önmagát, mivel a kifejezésben szereplő \1
az első zárójeles részkifejezés által lefedett darab visszautalása. Ha a szabályos kifejezésben egynél több zárójeles részkifejezés van, akkor így hivatkozhatunk rájuk: \2
, \3
és így tovább.
Az alapvető REs-ek esetében a részkifejezéseket \(
és \)
karakterekkel kell körülvenni, a (
és )
pedig önmagukban közönséges karakterek. A visszautalás jelzőjét a kiterjesztett reguláris kifejezésekhez hasonlóan használjuk.
Keresés a reguláris kifejezésekkel
A reguláris kifejezések közvetlen előnye a fájlrendszerekben és a szöveges dokumentumokban való keresés javítása. A find
parancs -regex
opciója lehetővé teszi, hogy a mappastruktúra minden útvonalát egy reguláris kifejezéssel teszteljük. Például,
$ find $HOME -regex '.*/\..*' -size +100M
100 megabájtnál (100 egységnyi 1048576 bájt) nagyobb fájlokat keres, de csak a felhasználó home mappáján belüli olyan elérési utakban, amelyek tartalmaznak egyezést a .*/\..*'-vel, azaz egy `/.
, amelyet bármilyen más karakter vesz körül. Más szóval, csak a rejtett fájlok vagy a rejtett mappákban lévő fájlok kerülnek listázásra, függetlenül attól, hogy a /.
milyen pozícióban van a megfelelő elérési útvonalban. Nagy- és kisbetű-független reguláris kifejezések esetén ehelyett az -iregex
opciót kell használni:
$ find /usr/share/fonts -regextype posix-extended -iregex '.*(dejavu|liberation).*sans.*(italic|oblique).*' /usr/share/fonts/dejavu/DejaVuSansCondensed-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansCondensed-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSans-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSans-Oblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-BoldOblique.ttf /usr/share/fonts/dejavu/DejaVuSansMono-Oblique.ttf /usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf /usr/share/fonts/liberation/LiberationSans-Italic.ttf
Ebben a példában a reguláris kifejezés olyan elágazásokat tartalmaz (kiterjesztett stílusban írva), amelyek csak a /usr/share/fonts
mappastruktúrában található betűtípusfájlokat listázzák. A kiterjesztett reguláris kifejezések alapértelmezés szerint nem támogatottak, de a find
lehetővé teszi, hogy a -regextype posix-extended
vagy -regextype egrep
kapcsolóval engedélyezzük őket. A find
alapértelmezett RE szabványa a findutils-default, ami gyakorlatilag egy alapvető reguláris kifejezés klón.
Gyakran szükséges, hogy a program kimenetét átadjuk a less
parancsnak, ha az nem fér ki a képernyőre. A less
parancs a bemenetet oldalakra bontja, egy-egy képernyőnyi részre, így a felhasználó könnyen navigálhat a szövegben fel és le. Ezenkívül a less
lehetővé teszi a felhasználó számára a reguláris kifejezéseken alapuló keresést is. Ez a funkció különösen fontos, mivel a less
az alapértelmezett lapozó, amelyet sok mindennapi feladathoz használnak, például a logfájlok ellenőrzéséhez vagy a kézikönyvek oldalainak megtekintéséhez. Egy kézikönyvoldal olvasásakor például a / billentyű megnyomásával egy keresési prompt nyílik meg. Ez egy tipikus forgatókönyv, amelyben a reguláris kifejezések hasznosak, mivel a kézikönyvoldal általános elrendezésében a parancsopciók közvetlenül az oldal margója után szerepelnek. Azonban ugyanaz az opció többször is előfordulhat a szövegben, ami a szó szerinti keresést kivitelezhetetlenné teszi. Ettől függetlenül a ^\\[*-o
— vagy még egyszerűbben: ^ *-o
— beírása a keresési promptban az Enter megnyomása után azonnal az -o
szakasz opciójára ugrik (ha létezik), így gyorsabban meg lehet keresni egy opció leírását.
Gyakorló feladatok
-
Milyen kiterjesztett reguláris kifejezésnek felelne meg bármelyik e-mail cím, például az
info@example.org
? -
Milyen kiterjesztett reguláris kifejezésnek felelnének meg a szabványos formátumú IPv4 címek, mint például a
192.168.15.1
? -
Hogyan lehet a
grep
parancsot használni az/etc/services
fájl tartalmának listázására, az összes kommentet (a `#-val kezdődő sorokat) elhagyva? -
A
domains.txt
fájl tartalmazza a tartománynevek listáját, soronként egyet-egyet. Hogyan lehetne azegrep
parancs segítségével csak a.org
vagy csak a.com
tartományokat listázni?
Gondolkodtató feladatok
-
Az aktuális mappában hogyan használhatnánk a
find
parancsban egy kiterjesztett reguláris kifejezést az összes olyan fájl keresésére, amely nem tartalmaz szabványos fájlvégződéseket (például a.txt
vagy.c
végződésű fájlokat)? -
A
less
parancs az alapértelmezett lapozó a hosszú szöveges fájlok megjelenítéséhez a shell környezetben. A/
beírásával egy reguláris kifejezést adhatunk meg a keresési promptban, hogy az első megfelelő találatra ugorjon. Ahhoz, hogy a dokumentum aktuális pozíciójában maradjon, és csak a megfelelő találatokat emelje ki, milyen billentyűkombinációt kell beírni a keresési promptba? -
A
less
-ben hogyan lehetne szűrni a kimenetet, hogy csak a reguláris kifejezésnek megfelelő sorok jelenjenek meg?
Összefoglalás
Ez a lecke a reguláris kifejezések általános Linux-támogatásával foglalkozott, amely egy széles körben használt szabvány, amelynek mintaillesztési képességeit a legtöbb szöveghez kapcsolódó program támogatja. A lecke a következő lépéseken ment keresztül:
-
Mi a reguláris kifejezés.
-
A reguláris kifejezések fő összetevői.
-
A különbségek a reguláris és a kiterjesztett reguláris kifejezések között.
-
Hogyan végezhetünk egyszerű szöveges- és fájlkereséseket a reguláris kifejezések segítségével.
Válaszok a gyakorló feladatokra
-
Milyen kiterjesztett reguláris kifejezésnek felelne meg bármelyik e-mail cím, például az
info@example.org
?egrep "\S+@\S+\.\S+"
-
Milyen kiterjesztett reguláris kifejezésnek felelnének meg a szabványos formátumú IPv4 címek, mint például a
192.168.15.1
?egrep "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"
-
Hogyan lehet a
grep
parancsot használni az/etc/services
fájl tartalmának listázására, az összes kommentet (a `#-val kezdődő sorokat) elhagyva?grep -v ^# /etc/services
-
A
domains.txt
fájl tartalmazza a tartománynevek listáját, soronként egyet-egyet. Hogyan lehetne azegrep
parancs segítségével csak a.org
vagy csak a.com
tartományokat listázni?egrep ".org$|.com$" domains.txt
Válaszok a gondolkodtató feladatokra
-
Az aktuális mappában hogyan használhatnánk a
find
parancsban egy kiterjesztett reguláris kifejezést az összes olyan fájl keresésére, amely nem tartalmaz szabványos fájlvégződéseket (például a.txt
vagy.c
végződésű fájlokat)?find . -type f -regextype egrep -not -regex '.*\.[[:alnum:]]{1,}$'
-
A
less
parancs az alapértelmezett lapozó a hosszú szöveges fájlok megjelenítéséhez a shell környezetben. A/
beírásával egy reguláris kifejezést adhatunk meg a keresési promptban, hogy az első megfelelő találatra ugorjon. Ahhoz, hogy a dokumentum aktuális pozíciójában maradjon, és csak a megfelelő találatokat emelje ki, milyen billentyűkombinációt kell beírni a keresési promptba?A Ctrl+K lenyomásával, mielőtt beírnánk a keresési kifejezést.
-
A
less
-ben hogyan lehetne szűrni a kimenetet, hogy csak a reguláris kifejezésnek megfelelő sorok jelenjenek meg?A & lenyomásával, majd a keresési kifejezés megadásával.