» »

Sed

Velika količina podatkov je in še dolgo bo v tekstovni obliki. HTML, XML, /etc/passwd in večina drugih konfiguracijskih datotek, celotna linux dokumentacija, PDF in DOC (bolj ali manj), mnoge knjige in sodbe sodišč, dolgočasni samoupravni sporazumi. V tem in še enem članku so predstavljene osnove orodja GNU sed, ki služi neinteraktivnemu urejanju teksta iz ukazne vrstice, vred z orisom njegovih zmogljivosti interpretacije regularnih izrazov.

sed pomeni stream editor. Namenjen je urejanju velike količine vrstic besedila. Zna jih brisati (ukazi d, D), pred njimi in za njimi vstavljati tekst (i\, a\) ter jih preoblikovati (s). Naprednejša uporaba zajema delo z več vrsticami naenkrat (n, N), uporabo začasnega pomnilnika (h, H, g, G) ter nekaj flow controla (:label, b, t). Lahko tudi prebere vsebino datotek (r) ali vanje kaj zapiše (w). Predvsem za debugging se uporablja ukaz l (dump pattern space).

Črke v oklepaju so ukazi, ki jih sed izvrši na trenutni vrstici. Ukaze se da pogojiti z uporabo regularnih izrazov (regex). Glavni uporabi sta luščenje podatkov iz vrstice (one-line ukaz) oz. filtriranje veliko ali velikih tekstovnih datotek (.sed datoteka z ukazi).

slika ukazne lupine

sed-a je težko narisati. O'Reilly mu je na naslovnici svoje bukve posvetil sliko vitkega lorija (pretegnjenec) in treba je reči, da mu kar pristoji. Gre za ozko orientirano orodje ukazne lupine - brez nepotrebne navlake dobro dela to, za kar je napisano, pa nič več. Zraven je slika ukazne lupine (shell). Ime izvira iz lupine kot vmesnika oz. ščita pred notranjimi deli operacijskega sistema - jedrom (kernel). Uporabnik tipka po shellu (oz. klika po GUI-ju), brez da bi se zavedal kompleksnih stvari, ki se dogajajo pod lupino. Podobno lahko sed uporabljamo na zelo visokem nivoju, brez da bi se zavedali, kako deluje. To nas lahko udari po glavi, kot je nakazano v odstavku "Pohlep", a večinoma težav ne bo.

Zakaj je to dobro

Sed je namenjen za spremembe tekstovnih datotek, ki se veliko ponavljajo. Če morate popraviti borih 5 vrstic, bo gotovo hitreje odpreti vi/joe/pico/whatever in zadevo narediti ročno. Če pa morate iz 5000+ HTML datotek odstraniti vse oznake <font>, <FONT> in <FoNt>, tega ne boste delali ročno, ampak z:

 
#! /bin/bash

IFS=$'\n'
for FILE in $(ls -1 *.html); do
	sed -i -e 's/<font[^>]*>//gi' ${FILE}
done

Kar bo, v grobem, preiskalo trenuten imenik za vse HTML datoteke (ls *.html), nato pa jih eno za drugo filtriralo skozi sed. Bral bo vrstico za vrstico in poiskal vse (/g) font, FONT, fOnT itd. (/i) tage v vrstici, ter jih izbrisal (zamenjal s praznim prostorom - //).

Se pravi - par popravkov bo šlo hitreje ročno, veliko enakih pa se že splača opraviti s sed-om. Namreč, pisanje in debuggiranje (!) skripte tudi nekaj traja. Če je tekst res močno strukturiran (CSV, XML), je že boljši awk ali xml parser. Če želite delati izračune ali kaj podobnega, sed odpade (ker ni programski jezik); za to so uporabni awk, perl, python, javo ali c ali kar pač uporabljate. Za prav specifične naloge obstajajo druga GNU orodja - tr, grep (grep x = sed -n '/x/p'), itd. Na sed je treba gledati kot na orodje - dobro je za določeno stvar, za ostale pa sploh ne.

Poganjanje

Obstaja več različic sed-a, ki se sicer bolj malo razlikujejo, a hudič je ravno v teh majhnih podrobnosti. Bistveno lažje bo, če vsi uporabljate GNU sed, dobljiv na spletni strani Free Software Foundation: <http://directory.fsf.org/sed.html>. Skoraj zagotovo je že nameščen na vašem sisemu; preverite s sed --version. Trenutna različica je 4.1.4, januar 2005.

Grobo gledano je to vse; zdaj pa praktični primer uporabe sed-a. Najprej potrebujete dostop do ukazne vrstice (oz. lupina = shell account) na kakšnem *nix strežniku. Nato morate sed-u povedati dvoje:

  • kje naj dobi podatke, in
  • katere ukaze naj izvede na njih.

rečni tok (stream)

Podatki za sed predstavljajo tok. oz stream; iz njega bere vrstice, dokler jih je le kaj prebrati. Vsaka vrstica je načeloma individualna enota in na na njej na novo izvede vse ukaze; ko konča, pozabi nanjo. Zato mu rečemo stream editor ali krajše sed. Iskreno bi mu lahko rekli tudi filter. No, tok je lahko datoteka ali pa izhod drugega programa, ki ga pošljemo skozi cev (shell pipe = |):

 
# sed -e 'ukazi' datoteka
$ sed -e 's/leva/desna/gi' vojaski_mars.txt
desna, desna, desna desna!
desna, desna, desna desna!
..

# nek program | sed -e 'ukazi'
$ cat plache.txt | sort | sed -e 's/000/ tisoč/'
Andrej Ribnik 222 tisoč
Petra Rozman 555 tisoč
Dule Savič 0 tisoč
..

Cev uporabljamo zlasti za kratke ukaze (neposredno za stikalom -e; glej spodaj), ker je ukaz skoncentriran na desnem koncu vrstice. Če se zmotimo, samo stisnemo tipko ↑ in že lahko popravimo ukaz. Tako zelo hitro napišemo skripto, kar je navsezadnje tudi naš namen. Ukaze je potrebno zapisati med enojne navednice (' '), ker le tako ukazni lupini preprečimo interpolacijo in podobno. Z dvojnimi navednicami (" ") se igrajte le, če res veste, kaj delate. Ena uporaba je npr. podajanje parametrov skripti. No, ukaz mora neposredno sledeiti stikalu -e. Morebitna druga stikala (zlasti -n, -i) morate zapisati pred -e.

Stikalo -n (invert) zamenja privzeto operacijo s p (print) na d (delete). Vrstica se ne bo izpisala. Če hočete, da jo sed kaj izpiše, mu morate to posebej povedati z stikalom /p na koncu ukaza:

 
$ sed -n -e '/H/p'
Hola mundo, Peter.
Hello World, Peter.
Guten Tag, meine Damen und Herren.

Privzeta operacija je zdaj izbriši vrstico (= ne izpiši je). Če pa slučajno naletiš na vrstico, ki vsebuje H (/H/), jo izpiši (/p). Kot že rečeno, je s tem sed ekvivalentem grep-u.

Daljše in bolj premišljene skripte pa grejo v svojo datoteko, navadno s končnico .sed. Datoteka vsebuje daljše ukaze ali več zaporednih ukazov. To ima več prednosti. Dodajamo lahko komentarje - vse v vrstici za znakom # sed smatra za komentar in prezre. Obdajanje z navednicami tudi ni več potrebno. Glavna prednost pa je večja berljivost. Poglejmo tale primer:

 
$$ cat html2wiki.sed
#! /bin/sed -f -i

# odstrani &nbsp;, <font> tage
# spremeni <td> v |
s/&nbsp;//g
s/<font[^>]*>//gi
s!</*td>>!|!gi

Nekoč sem rabil pretvoriti precej HTML strani v wiki sintakso. Za to je bilo potrebno iz strani pometati &nbsp;, odstraniti oznake <font> z vsemi morebitnimi atributi in pretvoriti oznake za celico v | (stolpci v wikiju se ločujejo z |). Če so ukazi zapisani vsak v svoji vrstici, se izvršijo zaporedoma in na vsaki vrstici. Se pravi, najprej vsi trije na prvi vrstici, nato vsi trije na drugi ... Poženemo pa jih z:

 
$ sed -f html2wiki.sed <datoteka>

Stikalo -f pomeni preberi ukaze iz te in te datoteke. Uporabimo lahko pri daljših ukazih, ki jih je bolj primerno zapisati v posebno datoteko. Po navadi ji damo končnico .sed. Spet: če je prva vrstica datoteke "#n", je to enako kot poganjanje sed -n -f - privzeti ukaz je d in ne p, in spet se ne bo nič izpisalo, če ne damo izrecnega ukaza /p.

Manjši trik je, da v prvo vrstico zapišemo #! /bin/sed -f. #1 (sha-bang) ukazni lupini pove, kateremu programu naj ponudi datoteko v zagon. Če tako skripto naredite zaženljivo (chmod +x html2wiki.sed), jo lahko zaganjate direktrno kot program - ./html2wiki.sed *.html.

sed vsako vrstico potem, ko na njej izvede vse ukaze, izpiše na standardni izhod. Tega lahko naprej zapišete v kako datoteko (shell redirect: sed -e '/H/d' pozdravi.txt > novi_pozdravi.txt). Stikalo -i oz. --in-place pove sed-u, da naj vse spremembe zapiše kar v trenutno datoteko, ne na standardni izhod. To zahteva pogum, ker bo izvorna datoteka prepisana in v primeru težav izgubljena. Skripto prej dobro preizkusite brez stikala. Za vsak primer lahko dodate --in-place=SUFFIX in sed bo najprej prekopiral izvorno datoteko nekaj v nekaj.SUFFIX. Backup.


Pogoji (/regex/), print (p) in delete (d)

Imamo datoteko pozdravi.txt in želimo izbrisati vrstice, ki vsebujejo veliko črko H:

 
$ cat pozdravi.txt
Lep večer
Hola mundo
Hello World
Guten Tag, meine Damen und Herren
Zdravstvuite

$ sed -e '/H/d' pozdravi.txt
Lep večer
Zdravstvuite

Kar pomeni:

  • Beri datoteko pozdravi.txt vrstico za vrstico;
  • Če vrstica ustreza regularnemu izrazu /H/, izvedi ukaz d - izbriši vrstico. Vrstica ustreza regexu, če vsebuje veliko črko H kjerkoli v vrstici (več o regularnih izrazih spodaj). S tem si končal delo na tej vrstici; preberi novo in začni znova.

Če pa ne vsebuje velike črke H, potem ne izvedi tega ukaza. Poglej, če je mogoče izvesti še kak ukaz na vrstici. Ni. Ker si na koncu, izvedi privzeto operacijo na vrstici - p (print). To izpiše trenutno vrstico. Ker vrstici Lep večer in Zdravstvuite ne vsebujeta črke H, ne ustrezata regexu /H/. Zato nista izbrisani, ampak izpisani. To je vsa logika dela z vrstico.

p (print) in d (delete) odločata, ali bo vrstica izpisana ali ne. Odločitev izvedeta na podlagi pogoja, ki se redoma zapiše pred ukazom. Pogoj je lahko številka vrstic, razpon vrstic ali regex:

  • 1d - izbriši prvo vrstico;
  • 22,40d - izbriši vrstice 22, 23, .. do 40;
  • /srebro|bron/d - izbriši vse vrstice, ki vsebujejo besedo srebro ali (|) besedo bron. Ostanejo le zlate medalje, ki se po privzeti operaciji izpišejo.
  • !<p class=first>!/</p>/d - izbriši vse vrstice od začetka odstavka !<p class=first> pa do vključno njegovega konca </p>. Tu namesto znaka / za zapis regexa uporabimo !, kar je priročno zlasti v html datotekah, ker ima tam / poseben pomen. Kot že rečeno, več o regexu spodaj.

Pogoj lahko negiramo s klicajem (!). /H/!d bi ohranilo vrstice, ki vsebujejo H - !d. Vse ostale vrstice pa bi izbrisalo (d).

Regex, ukazi in stikala

Regex je kratko ime za ti. regularne izraze (regular expressions), tj. izraze za opisovanje teksta. Predstavljajte si, da mulca prvič sploh pošiljate v trgovino. Opišete mu, kako zgledati tisto, kar mora prinesti - limone (ki so okrogle in take in take oblike) in nekaj medu (v steklenici, rjave barve) za svojega bolanega atija. Podobno lahko programu, ki razume regex, poveste:

kar iščem .. .. to regex najde
Najdi mi vse vrstice, ki vsebujejo besedo "limona" /limona/
ki se začnejo z "limona" /^limona/
.. končajo z "med" /med$/
vsebujejo vsaj tri zaporedne številke /[0-9]\{3\}/
vsebujejo tri črke (npr. januar), štiri številke (2006), in nič drugega (^$) /^[a-z]\{3\}[0-9]\{4\}$/

Regex je poglavje sam zase in o njem so napisane knjige z mnogo mnogo poglavji. Osnovna ideja pa je: med poševnicami (/regex/, lahko tudi drugimi znaki, npr. !regex2!) navedete, kaj mora biti v vrstici, da ta ustreza regexu. Če utreza, bo sed izvedel operacijo na njej (p, d, s, ..), sicer pa ne.

Osnovni element regexa je znak, npr a, e ali 3. Zaporedje znakov, npr. /lep dan/, pomeni, da morajo biti vrstici prisotni vsi v natančno določenem zaporedju. Kje v vrstici, načeloma ni pomembno. Lahko pa jih priklenemo na začetek vrstice (/^lep dan/), konec vrstice (/lep dan$/) ali oboje (/^lep dan$/; slednje pomeni, da mora biti lep dan edina vsebina vrstice.

Včasih si želite, da je prisoten znak iz vnaprej definiranega zaporedja. Takemu zaporedju se reče character class in pride med oglate oklepaje. [abc] pomeni enega od znakov a, b ali c. V razred lahko naštejete poljubne znake, npr [bfG] (enega od b, f ali G), posebej koristni pa so razponi ([A-Z0-9] katerakoli velika črka od A do Z ali katerakoli številka od 0 do 9). Uporabite lahko tudi ti. negiran character class (npr. /[^a]/), kar pomeni - najdi katerikoli znak, le da ne bo a. Poseben character class je . (pika), ki pomeni katerikoli znak, razen preloma vrstice (\n) (za zdaj to kar verjemimo). Se zelo pogosto uporablja, mestoma kar prepogosto. Dodatne razrede določa POSIX regex specifikacija.

Dodatno lahko poveste, da mora biti znakov prisotnih več v zaporedju (quantifiers). /a*/ pomeni 0 ali več a-jev (raje več), /\a+/ pomeni vsaj en a, raje več. /a\{4\}/ pomeni natanko 4 a-je. Oklepaje {} je treba escape-ati (dati prednje \), ker je sed primarno bil mišljen za filtriranje c kode, kjer imajo ti poseben pomen. To je edina resna zamera do sed-a, ki jo gojim.

Primer: Če iščete v datoteki serijsko kodo za MS Windows, uporabite regex <u>\([0-9A-Z]\{5\}\)</u>\{5\}. Kar pomeni: 5x stvar v oklepajih, en oklepaj pa pomeni zaporedje 5 znakov (velike črke ali številke). Oklepaji \( \) služijo grupiranju kode in backreferenciranju. Prvo smo ravno spoznali, naslednje sledi pri substituciji; še prej pa opozorilo o pohlepnih quantifierjih.

Velja tudi opozoriti, da je potrebno pred ukazno lupino (npr. bash) skriti znake, ki imajo poseben pomen v lupini sami. Zaradi je včasih potrebno določene znake escapati večkrat.

Pohlep

Tisti raje več pri quantifierjih pomeni, da bodo *, \+ in ? pobrali vse znake, ki jih lahko, dokler to ne bo na škodo celotnega regexa. Reče se, da so pohlepni (greedy) in včasih tega nočete. Npr. ko želite izbrisati iz vrstice vse, kar se nahaja med dvojnimi navednicami - s/".*"//g.

 
$ cat ripoff.txt
Za "hitrejšo" porjavitev se punce zatečejo po pomoč k prijaznemu osebju v solarij.
Tam kupiš "paket" za okoli 10.000,00 SIT, ki vključuje "ogromno" minut, recimo 100.

$ sed -e 's/".*"//g'
Za  porjavitev se punce zatečejo po pomoč k prijaznemu osebju v solarij.
Tam kupiš  minut, recimo 100.

Ehm .. druga vrstica je bistveno krajša, kot bi morala biti. To pa zato, ker ".*" ne ujame ločeno "paket" in "ogromno", kot smo želeli (stikalo /g - global). V prvi vrstici tega problem ni, ker je prisoten le en par navednic. Zanimivosti se začno v drugi vrstici. sed preverja znake enega za drugim, dokler ne pride do " pred besedo paket. Zdaj ima potrjen prvi del regexa. Nadaljuje z .*, ki grabi znake vse do konca vrstice (.. recimo 100.). sed zdaj poreče, okey, two down, one to go in začne iskati še zaključni ". Na koncu vrstice ga ni, zato začne jemati prejšnji sestavini regexa - .* znake stran, enega po enega, dokler ne pride do " za besedo ogromno. Takrat proglasi, da je našel vse sestavine regexa in izvede substitucijo. Dve citirani besedi plus vse vmes izginejo:

Besedilo: " paket" za okoli 10.000,00 SIT, ki vključuje "ogromno "
Pripadajoči del regexa:    /" .* "/

Prva predstava je verjetno: najdi ", nato išči karkoli (.*), dokler ne najdeš še enega ". Žal se to ne izgodi. Takšen quantifier bi bil len (lazy) in ga dejansko najdemo v nekaterih regex implementacijah (perl, awk) v obliki *?, +? oz. ??. sed ga ne podpira, morda ga kdaj bo. Rešitev za zdaj je, da namesto .* uporabite negirani character class - /"[^"]*"/, ki, kot že rečeno, pomeni: najdi ", nato mnogo česarkoli, le da ni " ([^"]*), in nato še enkrat ". To pa bo prav lepo delovalo. Pohlep imejte v mislih vedno, ko skušate najti kaj med dvema ločnikoma (delimiter). Če se lahko končni ločnik ponovi večkrat v vrstici, boste našli slednjega. Pohlep ima še eno stransko posledico, ki je lastna vsem regex programom z NFA regex pogonom - če je v regexu več z množilcem pogojenih komponent, regex preveri vse njihove medsebojne kombinacije, da najde najdaljši zadetek (grobo rečeno). Če se vam zazdi, da je se skripta izvaja neskončno dolgo, ste najverjetneje naleteli prav na ta problem.

Dajanje znakov nazaj se splošneje imenuje backtracking in pride v poštev še marsikje v regexu. Jemlje čas, ker je potrebno ponovno primerjati znak, ki smo ga že. Smiselno se mu je izogibati, če ga res ne rabite. Da bi se, morate vedeti, kako regex deluje in kakšna je razlika med pogonom NFA in DFA. Žal je to izven dosega članka.

Substitucija

Substitucija (zamenjava) je namenjena zamenjavi določenega dela vrstice. To jo naredi najpomembnejši ukaz med vsemi, zato ji bomo posvetili dodatno pozornost in ob tem povedali par stvari, ki se pritičejo vseh ukazov. Zato pozorno. A najprej enostavni - primer:

 
# sed -e 'ukazi' datoteka
$ sed -e 's/leva/desna/gi' vojaski_mars.txt
desna, desna, desna desna!
desna, desna, desna desna!
..

sed bere datoteko vojaski_mars.txt, vrstico za vrstico. Ko jo prebere, začne v njej iskati besedo leva. Ko jo najde, na njeno mesto postavi besedo desna. To, da sta besedi različnih dolžin, ga ne moti, sploh. Ko to naredi, bi načeloma končal. A ker je podano stikalo /g (global, zamenjaj vse primere), nadaljuje. V vrstici se postavi tik za besedo desna in začne znova iskati besedo leva. Zamenja jo. To dela tako dolgo, dokler ne zamenja vse primere beseda leva za desna. Ne moti ga niti, če piše Leva (prva beseda v stavku) ali LEvA ali kaj podobnega, ker je podano stikalo /i (case insensitive). In že jo vojaki skačejo po eni nogi ..

Še enkrat, kaj se dogaja v z vrstico:

Kdaj Vsebina vrstice
sveže naložena Leva, desna, leva, desna
po prvi zamenjavi desna, desna, leva, desna
po drugi zamenjavi desna, desna, desna, desna

Splošna oblika ukaza s je /pogoj/s/VZOREC/ZAMENJAVA/stikala.

Pogoj lahko ima vsak ukaz. Omeji vrstice, na katerih naj se poskusi izvesti substitucija. Lahko je regex (/mama/, številka vrstice (1, 14, $ - prva, štirinajsta, zadnja vrstica)) ali razpon vrstic (/od/,/do/s/od/do).

VZOREC je regex. Vsebuje znake, zaporedje znakov, character classes, quantifierje in oklepaje (\( in \)). Vsi razen slednjih se v zamenjavi obnaša natanko tako, kot v pogoju = kot smo povedali do zdaj. Oklepaji pa imajo poleg grupiranja še poseben pomen. Tekst, ki ustreza vzorcu med oklepaji, bo v ZAMENJAVI na voljo kot \1, \2, \3 in tako naprej. Te escape-ane števke imenujemo backreferences. Zakaj bi koristile? Recimo, da vas od vrstice zanima samo par ključnih stvari - npr. ime in priimer ter telefonska. Če znamo napisati VZOREC, ki to dvoje prebere ven, lahko vrstico očistimo vsega ostalega. Tako dobimo poročilo - kratek sestavek s ključnimi informacijami.

Recimo, da vaša spletna stran migrira iz enega foruma na drugega in rabite prenesti uporabniške račune v nov sistem. Nikjer sicer ne piše, da to morate storiti, zgleda pa povsem neprofesionalno, če ne (kajne?). Star forum je do konca čuden, seznam v bazi je cel skriptiran, pod /admin sekcijo pa obstaja html stran s tabelarnim prikazom vseh uporabiških računov. To želite pretvoriti v SQL za v novo bazo.

 
$ cat sodelavci.html
<table>
<tr><th>ime</th><th>uporabniško ime</th><th>geslo</th><th>telefonska</th></tr>

<tr><td>Andrej
Ribnik</td><td>aribnik</td><td>ribolov</td><td>031-666-666</td><tr>
<tr><td>Petra
Rozman</td><td>prozman</td><td>cosmopolitan</td><td>031-181-818</td><tr>
<tr><td>Dule
Savi.</td><td>dule</td><td>sex,drugs,rock&roll</td><td>041-000-000</td></tr>
</table>

Oz. v HTML:

imeuporabniško imegeslotelefonska
Andrej Ribnikaribnikribolov031-666-666
Petra Rozmanprozmancosmopolitan031-181-818
Dule Savičdulesex,drugs,rock&roll041-000-000

Nov forum rabi samo prve tri podatke, zato jih potegnemo ven:

#n

!<td>!s!<tr><td><u>\([^>]\+\)</u></td><td><u>\([^>]\+\)</u></td><td><u>\([^>]\+\)</u></td>.*!INSERT INTO auth VALUES('\2', '\3', '\1');!p

V skripti je kar nekaj novega, a dajmo se koncentrirati na že znano. Očitno rabimo samo vrstice s podatki, ostale pa hočemo ignorirati. Zato #n v prvi vrstici - izpisalo se bo le tisto, kar izrecno hočemo. Nato sledi pogoj <td>. Iz opazovanja html izvorne kode smo namreč ugotovili, da vrstice s podatki edine vsebujejo to oznako, zato jih ni težko določiti. In če vrstica vsebuje ta pogoj, na njej izvedemo substitucijo.

v substituciji je namesto znaka / uporabljen !. To ali kaj tretjega je povsem zakonito in pri html kodi tudi logično, saj sama po sebi vsebuje znak / za zapiranje oznak. Velja si zapomniti.

VZOREC vsebuje običajne znake in pa tri pare oklepajev. Tisto, kar ustreza tem parom, je potem na voljo v zamenjavi kot \1, \2 oz \3. Če kateri od oklepajev ne ujame ničesar, je njegova vrednost prazna. Oklepaje lahko tudi gnezdite - to ne spremeni ničesar. Backreferenco tvori vsak oklepaj, tudi če ste ga mislili samo za grupiranje, in za številko je važna samo pozicija, gledano z leve. Svojčas je bilo lahko največ 9 parov oklepajev, zdaj to več ni problem. Začete oglepaje morate zaključiti, sicer bo sed bridko zajokal. Napaka je tudi, če oklepaj začnete z \( in končate zgolj z ). Posebna backreferenca je znak &, ki vrne vse znake, ki jih je vzorec ujel. V našem primeru celo vrstico, ker smo z vzorcem opisali celo vrstico (glej .* na koncu). To je pogojno uporabno.

In smo pri ZAMENJAJ. Sem lahko damo poljuben tekst, brez zveze s tistim, kar je vzorec ujel. Večinoma seveda vključuje tudi backreference. Dodatno pravilo je, da v njem ni potrebno escape-ati večine znakov, ki jih v VZORCU moramo, npr. [, (, ", ' ipd. so zgolj dobesedni znaki za ZAMENJAJ.

Na koncu so stikala - po navadi /i za case insensitive, /g za global, /p za print. Za vse že vemo, kaj narede. Z /i varčujte, ker pomeni dvakrat toliko primerjav kot sicer (vsak znak v tekstu je potrebno primerjati v veliko in malo črko iz regexa) in zato polovico počasnejši regex.

insert (i\), append (a\), change (c\)

Ti trije ukazi vstavijo določen tekst pred, za oz. namesto trenutne vrstice. Imajo skupno obliko, precej drugačno od p ali d. Recimo, da želimo odstavke v html kodi obdati z vodoravno vrstico (<hr> - horizontal rule), kot je tale:


Ideja je, da poiščemo odstavek in predenj vstavimo vrstico s <hr>. V HTML svetu se odstavek začne s <p>, zato:

 
$ cat lociloPredOdstavek.sed
/<p>/ii\
<hr>

Kar pomeni: ko najdeš vrstico, ki vsebuje <p>, in to ne glede na velikost črk (/i), pred njo vstavi (i\) sledeče vrstice. Konec sledečih vrstic označuje prazna vrstica. Zaradi toliko prelomov vrstice je ukaz težko pisati neposredno v ukazni vrstici (se pa da: vsako vrstico je potrebno zaključiti z \).

Ločilo bi lahko vstavili tudi na konec odstavka (append). Če je koda pravilno formatirana; torej se vsak odstavek konča z </p>, bi zapisali:

 
$ cat lociloZaOdstavek.sed
!</p>!ia\
<hr>

Mogoče je posebej obravnavati prvo in zadnjo vrstico. V primeru vstavljanja pred odstavek si morda želimo, da je vodoravno ločilo tudi za zadnjim odstavkom. Podobno naredimo pri vstavljanju za odstavek, če želimo še vrstico pred prvim odstavkom:

 
$ cat lociloPredOdstavek2.sed
/<p>/ii\
<hr>


$i\
<hr>

Change uporabimo, ko želimo zamenjati celo vrstico ali, kar pri gornjih ne moremo, razpon vrstic. Spodaj je nadvse preprost SPAM filter, ki zamenja vsako kritično vrstico z opozorilom:

 
$cat blockSpam.sed

/\(viagra\)|\(cialis\)|\(herbs\)/c\
(to sporočilo je SPAM)

Ti trije ukazi se v glavnem uporabljajo za vstavljanje praznih vrstic in pa za pretvarjanje med različnimi formati zapisov.

Naslednjič ..

O sed-u vas čaka še en članek; tam bo govora o naprednih zmogljivostih (multiline pattern space, flow control) in predvsem bo veliko primerov uporabe regex-a.

Linux in Windows omrežje: Pobotajmo sosede

Linux in Windows omrežje: Pobotajmo sosede

Marsikdo, ki se je srečal z Linuxom in preživel z njim par dni, si je verjetno zaželel, da bi lahko uporabljal datoteke, ki jih daje v skupno rabo na drugem računalniku. In obratno, verjetno je želel dati v skupno rabo kake datoteke, ki jih ima na računalniku, kjer je nameščen ...

Preberi cel članek »

Perl RegEx

Perl RegEx

Sistemski administratorji, programerji in drugi zahtevnejši uporabniki se velikokrat srečujemo z zahtevo po obdelavi različnih kosov besedila takšnih in drugačnih oblik. Včasih gre za sezname, drugič za HTML strani, tretjič za velika besedila. Včasih želimo ...

Preberi cel članek »

Gstreamer -- švicarski nož za mešetarjenje z videom

Gstreamer -- švicarski nož za mešetarjenje z videom

Vsakdo si je že kdaj zaželel posneti kakšno malenkost s svojo spletno kamero in potem to stvar objaviti nekje v spletu. Marsikdo si je zaželel tudi predvajanja v živo. Spletna kamera, splet in subjekt pred kamero so tri poglavitne sestavine, ki jih potrebujemo za takšen projekt. Manjka še ena malenkost ...

Preberi cel članek »