A sed fontosabb parancsai
A fentiek után, ha csak röviden is, tekintsük át a sed leggyakrabban használt parancsait. Mivel a legtöbb parancs akár nulla, akár egy vagy két címmel is megadható, a címmegadást a következőek szerint jelöljük: ha a parancs csak egy címet fogad el, a /sorcím/ jelölést alkalmazzuk, ha kettőt, akkor a /címtartomány/ jelölést.
[címtartomány] s / minta / új_minta / [jelzők]
A címtartomány által meghatározott tartományban lévő sorokban behelyettesíti minta helyére új_mintát. Mind címtartomány, mind minta lehet reguláris kifejezés, az összes ott megismert metakarakter használható megadásukkor. Ha címtartomány reguláris kifejezés, és azonos minta-val, azaz minta megadása nem kötelező (pl. a /kutya/s//macska/g parancs minden, a kutya szót tartalmazó soron fog végrehajtódni, s ott minden kutyát lecserél macskára).
Behelyettesítéskor az alábbi jelentésmódosító flagek használhatóak:
n
1 és 512 közti szám, mely azt jelzi, hogy a behelyettesítést minta n-edik előfordulásán kell csak végrehajtanig
a mintatérben minta összes előfordulását lecseréli, nem csak a legelsőt, amit találp
kilistázza a mintatér tartalmátw file
a mintatér tartalmát a file állományba írjaA keresendő mintát a reguláris kifejezéseknél megismert módon adhatjuk meg, az ott megismert metakarakterek használhatóak.
Az alábbi metakarakterek a behelyettesítés jobb oldalán használhatóak.
&
minta értékének felel meg. Például s/Egyesült Államok/Amerikai &/ hatására sed a teljes névre egészíti ki slendrián megfogalmazásunkat.\n
(n egyjegyű egész szám); a mintában, tehát a behelyettesítés baloldalán a reguláris kifejezésben szereplő n-edik, \( .. \) karakterek közé zárt reguláris alkifejezésre hivatkozik. Például az s/\([A-Z][a-z][a-z]*\) \([A-Z]\.\) \([A-Z][a-z][a-z]*\)/\3 \1 \2/ parancs hatására a köznapi formában írt angolszász neveket alakítja át "hivatali használatra", például John C. Smith helyett Smith, John C. formára. (Lefordítva a fenti, valóban meglehetően ronda kifejezés valami olyasmit csinál, hogy "első reguláris alkifejezés legyen egy nagybetűvel kezdődő, egy vagy több kisbetűt tartalmazó karaktersorozat, ezt szóköz követi, a második alkifejezés egy nagybetű, melyet egy pont karakter követ; szóköz, majd a harmadik alkifejezés ismét csak nagybetű, egy vagy több kisbetűvel követve; ha a mintatérben talált a sed erre illeszkedő mintát, a harmadik, az első és a második alkifejezésre illeszkedő részét írja a kimenetre".)\
több funkciót is ellát, egyrészt a másik két metakarakter speciális jelentését nyomja el, másrészt többsoros behelyettesítés megadásánál használatos. Többsoros behelyettesítésre lehet példa az alábbi, ahol ha ased 's/\.ti \([0-9][0-9]*\) \(.*\)/\1. fejezet\
\2/'
parancs a
.ti 3 Az cserebogarak halhatatlansagarul
veretes szövegformázó makróutasítást a
3. fejezet
kétsoros formára hozza.
[
címtartomány]dA d parancs a kijelölt sort vagy sorokat törli (részleges törlésre a substitute parancsot használhatjuk). Egy dolgot kell ezzel kapcsolatban megemlítenünk: ha egy sort kitörlünk a mintatérből, a feldolgozás értelemszerűen megszakad, új sor kerül be a mintatérbe, s a sed scriptben szereplő parancsok annak feldolgozását kezdik meg.
Hozzáfűzés, beszúrás, változtatás
[sorcím]a\
szöveg
[sorcím]i\
szöveg
[címtartomány]c\
szöveg
Az a (append) parancs a mintatérben lévő sor végére, az i (insert) parancs a mintatérben lévő sor elejére, a c (change) parancs pedig a mintasor helyett illeszti be szöveget. Vigyázzunk arra, hogy mindhárom parancs többsoros, a parancs betűje után mindenképpen kell a backslash karakterrel védett soremelés, s kell a szöveg sorainak végén is, ha a beillesztendő szöveg többsoros. Szokatlan lehet az is, hogy a beillesztett szöveg kiíródik ugyan a kimenetre, de nem képezi részét a mintatérnek, s így a soronkövetkező script parancsok nem veszik figyelembe a sor feldolgozásánál. Mivel a c parancs törölte az eredeti mintateret, a szóban forgó sor feldolgozása éppúgy megszakad, mintha a d vagy q parancsot adtuk volna ki.
[címtartomány] y / str1 / str2 /
Az y (olvasd: transform... :-) parancs a mintatérbe kerülő sorokon karakterkonverziót hajt végre, mégpedig úgy, hogy mindazon karaktereket, melyek str1-ben szerepelnek, a mintatérben str2 ugyanazon pozíción lévő karakterével helyettesíti. (Gyakorlatilag a tr nevű Unix parancs mintájára.) Az alábbi sed parancs például minden számjegyet az N betűvel helyettesít a kimeneten:
sed 'y/0123456789/NNNNNNNNNN/'
[
címtartomány]pA p (print) parancs a mintatér tartalmát írja ki a mindenkori kimenetre. Miután a sed alapértelmezés szerint a mintatér minden sorát kiírja, a p parancsot a hibakeresés miatti kiíráson kívül a leginkább akkor használjuk, ha a sed parancsot a -n opcióval hívtuk meg, azaz alapértelmezésben letiltottuk a sorkiírást. (Ha például bizonyos részeket keresünk egy fájlban, s nem módosítani akarjuk, e megoldás a célravezetőbb.)
sed -n '/Linux/p'
A fenti parancs hatására a Linux szót tartalmazó sorok íródnak ki, a sed a többit eldobja.
[
címtartomány]nAz n (next) parancs hatására a mintatér pillanatnyi tartalmát sed kiírja a kimenetre, törli azt a mintatérből, majd beolvassa a soron következő sort, s azon folytatja a script parancsainak végrehajtását. Az alábbi parancs a '.' karakterrel kezdődő sorok után beolvassa a következő sort (vigyázat, ekkor az eredetit már a kimenetre tette!), s ha az újonnan beolvasott sor üres volt, törli azt:
sed '/^\./ { n
/^$/d }'
[
sorcím]r file[
címtartomány]w fileAz r (read) paranccsal a megadott cím után olvassa be a sed a mintatérbe file tartalmát; w (write) hatására a megadott címtartományon belüli rész kerül ki file-ba. Szintaktikai finomság: mindkét parancs pontosan egy szóközt követel meg a parancs és a fájlnév között; ha többet adunk meg, azt a fájlnév részének fogja tekinteni. Ha nem létező fájlt akarunk olvasni, a sed nem panaszkodik; hasonlóképp, nem létező fájl írásakor létrehozza azt, már létező tartalmát pedig felülírja. (A scripten belüli többszöri írások hozzáfűznek a fájlhoz.)
Az a, i és c parancsokhoz hasonlóan az r parancsra is igaz, hogy azonnal sed kimenetére kerül, s a script további feldolgozásában, mintaillesztésében nem vesz részt, a mintatérben maradó eredeti sor viszont igen. Egy példa ennek illusztrálására:
Tegyük fel, hogy van egy template nevű mintafájlunk, az alábbi szöveggel:
Kedves Ismeretlen, On cegunktol az alabbi ingyenes alomutazasok valamelyiket nyerte:
<cimlista>
Ezek igenybevetelehez mindossze az alabbiakat kell tennie...
A behelyettesítendő adatok pedig a helyszin.txt nevű állományban találhatóak:
Kanari szigetek repulogeppel
Korfu szigete autobusszal
Margit-sziget vízibusszal
Ha ezek után a sed-et a
sed '^/<cimlista>/ { r helyszin.txt ; d }' template
paranccsal hívjuk meg, akkor helyszin.txt szövege beszúródik a mintatér végére; a következő d parancs viszont a mintatér eredeti tartalmát törli, s így amikor a sed végzett az adott sorral, <cimlista> helyett a felkínált helyek listája jelenik meg a kimeneten:
Kedves Ismeretlen, On cegunktol az alabbi ingyenes alomutazasok valamelyiket nyerte:
Kanari szigetek repulogeppel
Korfu szigete autobusszal
Margit-sziget vízibusszal
Ezek igenybevetelehez mindossze az alabbiakat kell tennie...
N
D
P
Alábbi parancsaink az eddig ráolvasásszerűen ismételgetett dogmát kezdik ki, miszerint a sed sororientált editor, s egyszerre mindig csak egy soron végez műveleteket. Az N, D és P parancsok funkcionalitásukban egysoros megfelelőikkel azonosak, de mindegyik több soron dolgozik.
N
hatására sed még egy sort olvas a bemenetről, s a mintatér végére fűzi, annak régi tartalmát is megőrizve. A mintatérben lévő sorokat az újsor '\n' karakter választja el, s erre a mintakereséseknél hivatkozhatunk is. (Lásd a következő példát.)D
hatására a mintatérből egy sor, azaz a mintatér elejétől az első újsor karakterig terjedő rész törlődik. Ellentétben a d paranccsal, hatására nem olvas be új sort a mintatérbe, a feldolgozás viszont itt is újra a script elejétől folytatódik. Klasszikus példa a D parancs felhasználására, amikor sok üres sort tartalmazó bemenetről szeretnénk kiszűrni a felesleges sorokat:
/^$/ {
N
/^\n$/D
}
(A megoldás azon alapul, hogy üres sor beolvasása után a sed még egy sort beolvas, ha az is üres, az elsőt kitörli, s a script végrehajtása elölről indul; azaz mindez a beolvasás és törlés addig folytatódik, amíg vannak többszörös üres sorok, a script egyesével araszol végig a beolvasott sorokon. Ugyanez a d parancs felhasználásával páratlan számú üres sorokra nem működik, hiszen a d parancs a teljes mintateret, azaz mindkét sort törölte volna, a harmadik üres sor beolvasása után viszont nem üres sor jönne, s a script ekkor már nem törölné a harmadik üres sort.
P
hatására sed a mintatérből az első újsor karakterig terjedő részt írja a kimenetre. Önmagában nem gyakran használják, tipikus alkalmazása az előző példában szereplő, többsoros mintákat vizsgáló alkalmazásokban lehet. Ha ugyanis több egymás utáni sorban kell mintát keresni és behelyettesítést végezni, a legcélszerűbb megoldás egy olyan hurok felépítése, ahol megfelelő számú N paranccsal beolvassuk a mintatérbe a vizsgálandó sorokat, a megfelelő behelyettesítések után P paranccsal kiírjuk a mintatér módosított első sorát, majd ugyanazt töröljük a D paranccsal a mintatérből. A script megint elölről kezdi a feldolgozást, egy sorral odébb csúsztatva a "vizsgálati ablakot" a bemeneten. Alanti programocskánk (hasznosságáról valószínűleg nem kell győzködni a tisztelt olvasót :-) a netalán helytelenül írt Kisfejű Zordonbordon neveket cseréli ki az autentikus Kisfejű Nagyfejű Zordonbordonra, abban az esetben is, ha az a sorhatáron átnyúlva zordonbordonkodik:Ha a tesztfájlunk az alábbi:
Mikor tegnap erre jott Kisfeju
Zordonbordon,
morcosan nezett a Kisfeju Zordonbordon,
hogy nevet mindig rosszul mondom
a script pedig ez:
/Kisfeju/ {
N
s/Kisfeju\(.Zordonbordon\)/Kisfeju Nagyfeju\1/g
P
D
}
az eredmény ez lesz:
Mikor tegnap erre jott Kisfeju Nagyfeju
Zordonbordon,
morcosan nezett a Kisfeju Nagyfeju Zordonbordon,
hogy nevet mindig rosszul mondom
A script a Kisfeju szót tartalmazó sorok esetén beolvassa a következő sort is, s a kétsoros mintatéren globális behelyettesítést hajt végre, azaz a keresett minta összes előfordulását javítja: A Zordonbordon szót és az azt megelőző (szóköz vagy újsor) karaktert reguláris alkifejezésként megjelöltük, s a behelyettesítéskor ugyanezt tesszük vissza. Miután fenti módon az összes nevet kicseréltük, a mintatér első sorát (ami garantáltan javított), kiírjuk, majd töröljük a mintatérből, újabb sort olvasunk be, s újra kezdődik a script végrehajtása.
Az ideiglenes tárolótér és parancsai
A mintatéren kívül, ami mindig az aktuális sort tartalmazza, a sed egy másik területet is fenntart, ez a hold space (jobb híján nevezzük tárolótérnek). Ha egyes műveletek során arra volna szükségünk, hogy a mintatért elmentsük valahova, míg eredeti tartalmán műveleteket hajtunk végre, a tárolótérben tudunk egy ideiglenes kópiát képezni. A tárolóteret öt, nem címezhető parancs kezeli: h, H (hold), g, G (get) és x (exchange). A hold parancsok hatására a tárolótér tartalma a mintatérbe kerül, a get parancsok hatására pedig a tárolótér tartalma kerül vissza a mintatérbe. Az exchange parancs hatására a tárolótér és a mintatér tartalma megcserélődik. A kis- és nagybetűs parancsok között az a különbség, hogy h és g bemásoláskor felülírja a tároló-, illetve a mintatér tartalmát, H és G pedig újsor karakterrel elválasztva hozzáfűzi annak tartalmához (az újsor karaktert akkor is beteszi, ha a minta- vagy tárolótér éppen üres volt).
Elágazások, feltételes parancsvégrehajtás
Számos olyan sed parancsot láttunk már, melyek implicit módon megváltoztatják a scriptben a feldolgozás folyamatát; az alábbiakban olyan parancsokkal zárjuk ismerkedésünket a sed-del, melyek kimondottan a parancsvégrehajtás folyamatát szabályozzák.
A címkék használata teszi lehetővé, hogy általunk kijelölt tetszőleges helyre ugorhassunk egy sed scriptben. A címke egy maximum hét karakterből álló sorozat, melynek kettősponttal megelőzve, egymagában kell egy sorban szerepelnie, hogy a sed felismerje. (Rendkívül gyakori hiba, hogy a címke és a sor vége között néhány szóköz karaktert felejt az ember; ne tegyük, mert hét karakterig bezárólag ezeket is a címke részének tekinti a sed!) Ha egy parancsban címkére hivatkozunk, a script végrehajtása a címkét követő soron folytatódik. Például az alanti scriptrészlet hatására a loop3 címkére ugráskor a sed a mintatér tartalmát a tárolótér tartalmához fűzi, majd törli a mintatér első sorát:
:loop3
{
H
D
}
[
címtartomány]b[címke]A b (branch) parancs hatására a script vezérlése a label címkét követő sorra adódik át; ha nem adtunk meg címkét, a vezérlés a script végére kerül, magyarul a mintatér tartalma kiíródik és új sort olvas be a sed. (A b parancs és a címke között megengedett a szóközök használata.)
Például a
/^\.start/,/^\.stop/!b
s/\(.*\)/> \1/
script hatására a .start- .stop parancsokkal kijelölt rész kivételével (figyeljünk a negáló '!' karakterre!) nem csinál semmit, mert a vezérlést a script végére adja át. A .start és .stop parancsok közti részen pedig minden sort elé elhelyez egy '> ' szekvenciát.
A branch parancs segítségével hurkokat is tudunk csinálni:
:eleje
parancs1
/minta/b eleje
parancs2
A fenti programstruktúra alkalmazásával parancs1 mindaddig ciklikusan végrehajtódik, amíg a bemeneten van minta-ra illeszkedő sor; ha nincs, a script végrehajtása parancs2-vel folytatódik. Hasonló módon alakíthatóak ki egyéb ciklikus vezérlési szerkezetek is.
[
címtartomány]t[címke]A t (test) parancs hatására a vezérlés akkor kerül a megadott címke utáni sorra, ha előzőleg a kurrens sorban sikeres behelyettesítés történt. Akárcsak a b parancsnál, címke elhagyása esetén a vezérlés a script végére adódik át. Az alábbi script a .pa makróutasítás helyett egy soremelés (CTRL-L) karaktert szúr be, a .pp makróutasítás helyett pedig egy újsor karaktert. Mindkét esetben, ha sikeres volt a behelyettesítés, a vezérlés a tovabb címkétől folytatódik; gyakorlatilag tehát egy C vagy shell nyelvi case konstrukciót szimulálunk:
/^\.pa.*/s//^L/
t tovabb
/^\.pp.*/s//\n/
t tovabb
... egyeb parancsok
:tovabb
A fentiekben csak igen vázlatos áttekintését nyújtottuk a sed-nek, de azt talán sikerült bizonyítanunk, hogy rendkívül sokoldalúan használható eszköz lehet a felhasználó kezében. Csak bátorítani tudunk mindenkit használatára, mert a kezdeti erőfeszítések sokszorosan kifizetődnek majd az első komolyabb szövegátalakítás alkalmával.