Jak na hromadnΘ nahrazovßnφ textu?

11. 5. 1999on-line novΘ okno dom∙ p°edchozφ Φlßnek nßsledujφcφ Φlßnek

UrΦit∞ se vßm ji╛ stalo, ╛e jste pot°ebovali v n∞kolika souborech zm∞nit text podle vßm znßmΘho pravidla. Mo╛nß jste spustili sv∙j oblφben² textov² editor a zaΦali jste ruΦn∞ nahrazovat v²skyty textu XYZ textem ABC. Mo╛nß jste pou╛ili funkci Replace, zadali oba texty a pak jenom potvrzovali v²m∞nu. Pokud t∞ch soubor∙ bylo n∞kolik (slovy mΘn∞ ne╛ p∞t), pak se to dß zvlßdnout v rozumnΘ dob∞ a p°i p°ijatelnΘ nßmaze. Ale co kdy╛ t∞ch soubor∙ je sto? Nebo padesßt tisφc? Pro tento p°φpad vßm nabφzφm mal² progrßmek.

Tento progrßmek se sklßdß ze dvou soubor∙ - perlovskΘho skriptu odstran a souboru s p°φkazy pro editor VI. Ne, nelekejte se, nebudete se muset uΦit pracovat s tφmto klasick²m editorem. Jen jej budeme vyu╛φvat. V nßsledujφcφm textu budu °e╣it problΘm odstran∞nφ absolutnφch adres v odkazech pro html soubory.

Skript
Perlovsk² skript je velice trivißlnφ. Vytvo°te si soubor odstran (nebo pou╛ijte jin² nßzev) a vlo╛te do n∞j nßsledujφcφ text: (tip pro zaΦßteΦnφky: ta╛enφm my╣i p°i stisknutΘm levΘm tlaΦφtku text oznaΦte. Pak ve vedlej╣φm okn∞ Φi konzoli stisknutφm prost°ednφho tlaΦφtka my╣i text vlo╛φte do n∞jakΘho editoru.)

#!/usr/bin/perl
$soubory = `find . -name "*.html"`;
@file = split(/^/,$soubory);
foreach(@file)
{
        $neco = $_;
        chop $neco;
        print "Zpracovßvßm soubor $neco";
        system "vi -f -s /home/literakl/VI $neco";
}

Pak soubor ulo╛te a nastavte u n∞j prßvo na spou╣t∞nφ (p°φkazem chmod +x odstran). Perlov╣tφ guru si mo╛nß budou rvßt vlasy p°i pohledu na zdrojov² k≤d nad jeho neefektivnostφ, pro mn∞ je ale d∙le╛itΘ, ╛e to funguje. Te∩ si jej trochu rozeberme. Prvnφ °ßdek spou╣tφ interpretr perl. Pokud jej nemßte v adresß°i /usr/bin, pak zm∞≥te cestu.

Na druhΘm °ßdku do prom∞nnΘ $soubory vlo╛φme v╣echny soubory, kterΘ na╣el program find. Tento program mß obrovskΘ mo╛nosti, proto doporuΦuji p°eΦφst si jeho manußlovou strßnku (man find). Pro na╣e ·Φely bude postaΦujφcφ nßsledujφcφ popis.

Prvnφ parametr urΦuje adresß°, kde se mß zaΦφt vyhledßvat. V tomto p°φpad∞ teΦka oznaΦuje aktußlnφ adresß°. Samoz°ejm∞ byste ale mohli pou╛φt absolutnφ cestu. Nap°φklad /home/literakl/public_html/. Dal╣φm parametrem je dvojice -name "*.html". Tento parametr urΦuje, ╛e se vyberou v╣echny soubory, jejich╛ jmΘno spl≥uje druhß Φßst podle shellovskΘ konvence. Tedy m∙╛ete pou╛φt zßstupnΘ znaky jako jsou nap°φklad hv∞zdiΦka (zastupuje nulu a vφce libovoln²ch znak∙), otaznφk (zastupuje p°esn∞ jeden libovoln² znak) a hranatΘ zßvorky ([aeiouy] zastupuje jeden z vypsan²ch znak∙, v tomto p°φpad∞ samohlßsky, [^aeiouy] zastupuje jeden znak, kter² nenφ v uvedemΘ mno╛in∞). Tak╛e v tomto p°φpad∞ se vyberou v╣echny soubory konΦφcφ na .html v aktußlnφm adresß°i a v╣ech jeho podadresß°φch.

Ve zbylΘ Φßsti skriptu se jedna prom∞nnß rozd∞lφ do pole promm∞n²ch a v cyklu se pro ka╛d² nalezen² soubor vypφ╣e jeho jmΘno a zpracuje programem vi. ╚ßst za znakem < samoz°ejm∞ nahra∩te sprßvnou cestou.

Soubor s p°φkazy
Do tohoto souboru se vklßdajφ p°φkazy pro editor vi. Nazv∞te si jej a umφst∞te, jak a kam chcete. Nezapome≥te pak ale upravit p°edposlednφ °ßdek skriptu. Text souboru VI mß obecn∞ nßsledujφcφ tvar:

:g/XYZ/s//ABC/g
:wq

Na prvnφm °ßdku je regulßrnφ v²raz, na druhΘm p°φkaz pro zapsßnφ zm∞n a ukonΦenφ Φinnosti editoru vi. Pokud vßm regulßrnφ v²razy nic ne°φkajφ, zkuste spustit vi a v n∞m napsat :help pattern a zmßΦknout enter. Jinou mo╛nostφ je manußlovß strßnka regulßrnφch v²raz∙ pro perl - man perlre.

P°i b∞╛nΘ prßci nahradφte text XYZ hledan²m textem a ABC nov²m textem. Pokud se vßm nechce proΦφtat manußly k regulßrnφm v²raz∙m (v°ele doporuΦuji je p°eΦφst), snad vßm pom∙╛e nßsledujφcφ v²tah, kter² mß daleko k ·plnosti.

XYZ m∙╛e b²t b∞╛n² text, kter² hledßte. Potom algoritmus porovnßvß pro╣l² text s po╛adovan²m textem a nalezne-li shodu, zm∞nφ jej na ABC. V XYZ ale mohou b²t zßstupnΘ znaky. Hv∞zdiΦka stejn∞ jako v shellu nahrazuje libovoln² poΦet libovoln²ch znak∙. TeΦka nahrazuje jeden libovoln² znak; tj. mß stejn² v²znam jako otaznφk v shellu. HranatΘ zßvorky se chovajφ takΘ stejn∞ jako v shellu, vybφrajφ jeden platn² znak z uvedenΘ mno╛iny. Pokud chcete najφt znak *,.,[ nebo ], napi╣te p°ed nφm zp∞tnΘ lomφtko. To ru╣φ v²znam specißlnφho znaku.

P°φklady:

Dal╣φm specißlnφ znakem je ^, pokud nenφ pou╛it jako negace ve v²Φtu znak∙. Pak mß v²znam zaΦßtku °ßdku. Obdobn∞ znak $ ukazuje na konec °ßdku. Dvojice < je zase nßhradou zaΦßtku slova a > pak konce slova.

P°φklady

To by snad mohlo pro ·vod staΦit. Te∩ se vrhn∞me zpßtky na nß╣ p°φklad. V html souborech, kterΘ jsme si stßhli, autor pou╛φvß absolutnφ odkazy i s nßzvem jeho serveru. Jen╛e my nejsme p°ipojeni na internet a tak nßm prohlφ╛eΦ pφ╣e, ╛e nem∙╛e najφt ten server. A navφc p°φstup na disk je rychlej╣φ ne╛ p°es internet (pokud nesedφte u TEN-6000 :) ). Tak╛e pot°ebujete odstranit nap°φklad °et∞zec http://www.domena.org/~uzivatel/adresar/ v n∞kolika desφtkßch soubor∙. Soubor VI pak bude mφt nßsledujφcφ tvar:

:g/HREF="http://www.domena.org/~uzivatel/adresar//s//HREF="../../g
:wq

V╣imn∞te si zp∞tn²ch lomφtek ru╣φcφch v²znam specißlnφch znak∙. V Φßsti XYZ hledßme °et∞zec HREF="http://www.domena.org/~uzivatel/adresar/ a ten nahradφme °et∞zcem HREF=". Tφmto zp∙sobem nahradφme skuteΦn∞ jen odkazy, nikoliv text. Po spu╣t∞nφ skriptu odstran ve sprßvnΘm adresß°i se nahradφ v╣echny v²skyty a za n∞kolik sekund je tato prßce hotova.

Varovßnφ

Regulßrnφ v²razy mohou d∞lat n∞co jinΘho, ne╛ jste zam²╣leli. Proto, pokud nejste guru p°es regulßrnφ v²razy, rad∞ji si po°i∩te zßlo╛nφ kopii dat. Varoval jsem vßs.

Nev²hody



V²hody Tento skript se hodφ v╛dy, kdy╛ pot°ebujete ud∞lat nahrazenφ v mnoha souborech. Obvzlß╣t∞ se hodφ p°i sprßv∞ webovsk²ch strßnek. U╛ se nebudete muset bßt zm∞ny struktury adresß°∙ na va╣em rozlehlΘm webovskΘm serveru. Pravda, n∞co podobnΘho a p°φjemn∞j╣φho jsem nedßvno vid∞l v Homesitu. Ani nevφm, kdy to ode mne zkopφrovali :). Snad to n∞komu pom∙╛e.

Leo╣ Literßk
literakl@seznam.cz
Linux Hardware

Autor: Leo╣ Literßk (jinΘ Φlßnky tohoto autora)
Sekce: Praxe
Souvisejφcφ Φlßnky:


Diskuse

11. 5. 1999 09:13:04 - Jde to i elegantneji. Misto '... (Petr Brouzda)
Jde to i elegantneji. Misto 'vi' pouzit 'sed' a je to na jednu dlouhou prikazovou radku zacinajici findem. PB.

11. 5. 1999 12:48:07 - Re: Jde to i elegantneji. Misto '... (Ond°ej Solansk²)
Nebo vyu╛φt pro nahrazovßnφ jenom Perl: #!/usr/bin/perl while (glob('*.html')) { open (SOURCE,$_) or die '$!\n'; print 'Zpracovßvßm soubor ','$_,'\n'; open (TARGET, ')$_.new') or die '$!\n'; while ((SOURCE)) { chomp; s/nejaky text/za nejaky text/g; print TARGET $_,'\n'; }; close SOURCE; close TARGET; } while (glob('*.new')) { $old = $_; s/\.new//; rename $old,$_; }

11. 5. 1999 12:56:29 - Re: Jde to i elegantneji. Misto '... (Ond°ej Solansk²)
Poznßmka : Na °ßdcφch open (TARGET, ')$_.new') or die '$!\n'; while ((SOURCE)) { jsou vnit°nφ zßvorky ostrΘ, nikoliv kulatΘ, za co╛ nemohu - tak se to p°eneslo.

11. 5. 1999 14:47:03 - Za vsechny, kteri nepouzivaji ... (Jakub Steiner)
Za vsechny, kteri nepouzivaji sed a byl pro ne tento clanek nesmirne uzitecnym dekuji autorovi.

11. 5. 1999 17:07:17 - Mam k tomu clanku par poznamek... (Robert Wolf)
Mam k tomu clanku par poznamek: A) zbytecne pouzivani perlu. stejne to lze udelat i v shellu for L in `find . -name *.html`;do sed -e '...';done jedna radka a je to OK (u toho find jsou zpetny apostrofy) a pokud to chcete jenom v aktualnim adresari, tak staci pouze sed -e '...' B) vetsina lidi asi pouziva Linux a obvykle RedHat nevim jak jinde ale na RH je vi akorat link na vim takze jestli ma vi a vim jiny regularni vyrazy, tak to nebude fungovat, navic vim ma trosku odlisne reg.vyrazy od perlu, takze pro perl se je ucte z man perlre a pro vim se je ucte z helpu vimu C) dalsi vec jsou priklady reg.vyrazu: vyraz ma*ka v zadnem pripade (ani ve vimu ani v perlu) nenajde slova matka, maska. totiz s reg.vyrazama je to asi takhle: . znak tecka zastupuje jakykoliv znak * udava, ze se PREDCHOZI znak muze opakovat 0 a vickrat + udeva opakovani PREDCHOZIHO znaku 1 a vicekrat ? udava opakovani PREDCHOZIHO znaku 1 nebo 0 krat {,n} predchozi znak se bude opakovat max. N-krat {m,n} predch.znak se musi opakovat minimalne M-krat a maximalne N-krat {m,} znak se musi opakovat minimalne M-krat {m} znak musi byt presne M-krat pokud chcete opakovat posloupnost treba ABC, tak se ta posloupnost uzavre do kulatych zavorek a za zavorku se prida pocet, napr. (ABC){3,5} najde posloupnost trojice ABC a to kdyz bude tahle trojice za sebou trikrat az petkrat, cili ABCABC ne ABCABCABC jo ABCABCABCABC jo ABCABCABCABCABC jo a delsi uz zase ne pokud chcete nechat hledat znaky *,+,(,),/ atd., musite pred ne vlozit znak \, znak / se pouziva na otevreni a uzavreni regularniho vyrazu, ale muzete misto nej pouzit i jiny znak a pak muzete v reg.vyrazu pouzit pouze znak / bez \. napr. pri hledani textu http:// je dobre pouzit vyraz !http://! , kde zavorky reg.vyrazu bude znak vykricnik je toho jeste vice, ale to by bylo opravdu na vlastni clanek. Tohle totiz plati u PERLu, VIM pouziva specialni znaky trosku jinak, napr. co v PERLu znamena znak +, to se ve VIMu musi napsat jako \+ atd. a take jeste zalezi na nastaveni magic. Prostudujte skutecne man perlre, man grep, man sed a help ve VIMu. D) navic tenhle vyraz ma dve chyby: g/HREF='http://www.domena.org/~uzivatel/adresar//s//HREF='/g 1) / nelze pouzit v reg.vyrazu, kdyz je / jako zavorky reg.vyrazu. Musi se bud pouzit jine zavorky nebo se pred znak / v reg.vyrazu musi zadat \ 2) znak ~ ma ve vimu specialni vyznam, takze taky potrebuje pred sebe znak \ E) pokud by nekdo chtel delat s vim a sed na MSDOS/WIN tak muze, staci jit na adresy ftp://ftp.vslib.cz/disk2/vim a sed je v ftp://ftp.zcu.cz/pub/simtelnet/gnu/djgpp/v2gnu/sed302b.zip Zdravim Wolf. P.S.: Sorry za preklepy a pripadne chyby, ale melo by to byt OK, ale nejsem regularni a VI guru:-) takze chybicka se mozna vloudi

11. 5. 1999 17:16:32 - Re: Mam k tomu clanku par poznamek... (Robert Wolf)
Tady to pokracuje!!!! Tohle totiz plati u PERLu, VIM pouziva specialni znaky trosku jinak, napr. co v PERLu znamena znak +, to se ve VIMu musi napsat jako \+ atd. a take jeste zalezi na nastaveni magic. Prostudujte skutecne man perlre, man grep, man sed a help ve VIMu. D) navic tenhle vyraz ma dve chyby: g/HREF='http://www.domena.org/~uzivatel/adresar//s//HREF='/g 1) / nelze pouzit v reg.vyrazu, kdyz je / jako zavorky reg.vyrazu. Musi se bud pouzit jine zavorky nebo se pred znak / v reg.vyrazu musi zadat \ 2) znak ~ ma ve vimu specialni vyznam, takze taky potrebuje pred sebe znak \ E) pokud by nekdo chtel delat s vim a sed na MSDOS/WIN tak muze, staci jit na adresy ftp://ftp.vslib.cz/disk2/vim a sed je v ftp://ftp.zcu.cz/pub/simtelnet/gnu/djgpp/v2gnu/sed302b.zip Zdravim Wolf. P.S.: Sorry za preklepy a pripadne chyby, ale melo by to byt OK, ale nejsem regularni a VI guru:-) takze chybicka se mozna vloudi

11. 5. 1999 17:24:16 - Re: Mam k tomu clanku par poznamek... (Robert Wolf)
A vloudila se chybicka: V bode A) jsem chtel rict, ze pomoci sedu pouze v aktualnim adresari to jde pomoci prikazu sed -e '...' *.html kde ... je reg.vyraz neco jako s!HREF='http;//www.server.org/\~uzivatel/!HREF='!gi to g na konci znamena globalne-vickrat v jedne radce, coz se muze stat, ze na jedne radce bude vice odkazu a to i znamena ignore-case, coz je dost dobre, protoze pokud nekdo zapise http misto HTTP, tak uz by to nas stary regularni vyraz nenasel Wolf


on-line novΘ okno dom∙ p°edchozφ Φlßnek nßsledujφcφ Φlßnek