Linux E X P R E S

Facebook

Užitečné unixové programy

V minulém čísle jsme si představili makroprocesor m4. Avšak Linux a Unixové systémy obsahují standardně mnoho dalších, užitečných nástrojů. Stručně si tyto nástroje popíšeme, abychom si poté mohli nastínit jejich použití při tvorbě komplexnějších systémů.


Regulární výrazy

Regulární výrazy jsou velmi mocný nástroj. Bohužel se implementace regulárních výrazů dosti liší (např. Perl vs. Unix).

Regulární výrazy jsou řetězce znaků, které přesně definovaným způsobem vybírají podřetězce z jiných řetězců. Regulárním výrazům se věnuje např. standard IEEE 1003.1-2004, známý též jako POSIX. V Unixu se dají použít např. při vyhledávání v souborech pomocí nástroje grep nebo pro modifikace libovolných textových dat pomocí programů sed a awk.

Mezi nejužitečnější programy patří dvojice sed a awk. Než si je blíže popíšeme, zaměříme se na regulární výrazy, na kterých je jejich činnost založena.

POSIX je souborné označení pro rodinu standardů specifikovaných organizací IEEE. Definují aplikační rozhraní (API) pro software kompatibilní mezi variantami unixových operačních systémů. Projekt původně vznikl v roce 1985. Pojem POSIX byl navržen Richardem Stallmanem, má být zároveň zpětným akronymem pro Portable Operating System Interface, X vyzdvihuje unixový původ standardů. Poznámka redakce, volně podle http://en.wikipedia.org/wiki/POSIX.

Základní jednotkou regulárního výrazu je písmeno. Pravidlo i najde v řetězci Linux právě jedno malé měkké i (zde stojí za to zmínit se, že regulární výrazy rozlišují velká a malá písmena). Zástupným znakem je znak . (tečka). Výraz .o. najde výskyt např. rok, kop, mok a libovolné další třípísmenné slovo, které má uprostřed písmeno o. Tímto způsobem můžeme vyhledávat i celá slova, takže např. řetězec tisk je také regulárním výrazem, ačkoliv neobsahuje žádné řídicí znaky.

Zpravidla hledáme více (a někdy i méně) znaků než jeden. V regulárních výrazech jsou speciální znaky, které nám umožňují přesně specifikovat, kolik znaků chceme nalézt. Dva z těchto znaků známe již z dob DOSu - * (hvězdička) a ? (otazník). Hvězdička vyjadřuje, že znak nebo skupina znaků (viz dále) těsně před ní se buď vůbec nemusí vyskytovat, nebo se může opakovat libovolně. Proto např. regulární výraz bar.* najde slova bar, barva, barevný, barvit atd.

Otazník znamená buď žádný, nebo jeden výskyt. Prakticky tento význam můžeme využít při hledání např. slova color či colour - výraz má tvar colo.?r ; ještě jeden znak má podobný význam, a to znak + (plus). Ten najde jeden a více předcházejících výskytů. Například výraz AB+A najde ABA, ABBA, ABBBA atd.

Další operátor počtu výskytu jsou složené závorky, v nichž je interval minimálního a maximálního počtu výskytu znaků. Pokud bychom tedy chtěli upravit předchozí výraz tak, aby našel jen řetězce ABA a ABBA a žádné jiné, přepsali bychom jej takto: AB{1,2}A . Pokud napíšeme pouze jedno číslo a vynecháme čárku - AB{2}A - výraz najde jen řetězec ABBA, protože samotné číslo v závorkách znamená "najdi právě tolik výskytů". Pokud napíšeme čárku, ale druhé číslo nikoliv, znamená to "najdi tolik a více výskytů". V extrémním případě bychom mohli symbol + definovat jako {1,} .

Velmi důležitou součástí regulárních výrazů je seskupování a alternativy. Seskupování umožňuje pracovat místo s jedním znakem se skupinou znaků (např. a(bc)+ by našel a, abc, abcbc, abcbcbc...). Alternativu je lepší si předvést nejprve na příkladu. Předpokládejme, že zpracovávám text a v textu se někde vyskytuje jméno Haendel. Ovšem nevíme, zda je psáno takto, nebo s přehláskou (Händel). Není nic jednoduššího než napsat H(ae|ä)ndel . Jednotlivé možnosti alternativ jsou odděleny znakem | (roura). Nechť si čtenář vyzkouší napsat regulární výraz, který najde slova děd, dědeček, pradědeček, praprapraděd, … (jedno ze správných řešení je (pra)*děd(eček)? ).

Dalším důležitým prvkem jsou hranaté závorky. Vystupují jako jeden znak, avšak mohou vyjmenovat množinu znaků, kterou mají (nebo nemají) najít. Např. výraz [sz]práva najde jako slovo správa, tak slovo zpráva. Můžeme také určité znaky z hledání vyloučit pomocí znaku ^ (stříška), takže např. výraz [^a-r]práva najde sice také zpráva a správa, ale také xpráva, ale nenajde epráva, protože znak e je v intervalu a-r a tento interval jsme zakázali. Oba přístupy je možné kombinovat, čili bychom mohli vytvořit výraz [^a-rtuvwxy]práva , nebo [^a-rt-y]práva , oba najdou původní dvě slova. Norma POSIX navíc zavedla pojmenované intervaly ve tvaru [:jméno:] :

[:upper:] - velká písmena ([A-Z])
[:lower:] - malá písmena ([a-z])
[:alpha:] - malá i velká písmena ([A-Za-z])
[:alnum:] - malá, velká písmena a číslice ([A-Za-z0-9])
[:digit:] - číslice ([0-9])
[:xdigit:] - hexadecimální číslice ([0-9A-Fa-f])
[:punct:] - interpunkce ([.,!?:...])
[:blank:] - mezera a tabulátor ([ \t])
[:space:] - prázdné znaky (jak horizontální, tak vertikální) ([ \t\n\r\f\v])
[:cntrl:] - řídicí znaky
[:graph:] - jakékoli tisknutelné znaky ([^ \t\n\r\f\v])
[:print:] - tisknutelné znaky a mezera ([^\t\n\r\f\v])

Tyto skupiny je možné kombinovat třeba takto: [[:upper:]abcd] , což najde libovolné velké písmeno nebo malé a, b, c nebo d. Důležitým prvkem jsou také označené části výrazu. Pokud určitou část výrazu uzavřeme do kulatých závorek (platí o nich to samé, co o složených závorkách), můžeme se na tuto část odkazovat ve tvaru \n , kde n je celé kladné číslo. Podvýrazy jsou číslovány od jedničky. Můžeme si to názorně demonstrovat tímto výrazem: (.)(.)\2\1 - tento výraz najde např. tyto řetězce: ABBA, SCCS, xyyx, atd.

V Unixu je zvykem zapisovat regulární výrazy mezi lomítka, avšak regulární výrazy se dají použít např. i v jazyce Java, ve kterém takto formátované být nemusí (resp. nesmí, jinak by měly jiný význam).

Posledním prvkem, o kterém se v tomto úvodu do regulárních výrazů zmíním, jsou znaky ^ (stříška) a $ (dolar). Stříška znamená začátek a dolar konec řádku, proto např. výraz ^$ najde prázdný řádek, ^abcd$ najde řádek s jediným řetězcem abcd.

Sed

Zkratka sed pochází ze slov "stream editor". Vychází z editoru ed, který je předchůdcem editoru vi(m). Zatímco ed dovoloval jak řádkový tak vizuální (celoobrazovkový) režim (v novějších verzích) a byl ovládán zpravidla interaktivně, sed je určen pro dávkové zpracování. Hlavní síla sedu tkví právě v regulárních výrazech. Umožňuje pomocí jednoho a více regulárních výrazů transformovat vstupní soubor na výstupní. Také umožňuje jednoduché větvení.

Ještě uvedeme příklad jiného skriptu, který způsobí vymazání prázdných řádků: sed /^$/d

Jeden z nejužívanějších forem použití sedu je jednořádkový skript, který se zpravidla nepíše do souboru. Prakticky použitelných skriptů, včetně různých číslování řádek, vypouštění prázdných řádek atd. je celá řada. Ty nejlepší a nejužívanější je možné najít na internetu jako tzv. "sed one-liners", případně na stránce http://sed.sourceforge.net.

Upozornil bych rád na fakt, že podle normy POSIX (viz výše) existují dva druhy regulárních výrazů: základní a rozšířené. V základním regulárním výrazu by měly být složené závorky uvozeny zpětným lomítkem (čili takto: AB\{1,2\} ). V rozšířeném formátu se u složených závorek zpětné lomítko nepoužívá.

Možnosti sedu si předvedeme na jednoduchém příkladu. Máme adresář plný MP3 souborů, který chceme vypálit na CD do našeho discmanu. Ovšem z manuálu víme, že jméno souboru má být trackXXX.mp3, jinak nemusí být soubor discmanem rozpoznán. Naše soubory mají jméno ve tvaru XX - Album - Jméno skladby.mp3. (XX značí číslo stopy). Pokud tyto soubory budeme chtít překopírovat na výše uvedený formát, vyřeší to následující skript, zadaný v terminálu (BASHi):

for jmeno in *.mp3
do
  cp $jmeno /tmp/`echo $i | sed "s/\([0-9]\{2\}\).*/track0\1.mp3/"`
done

Regulární výraz mezi první dvojicí lomítek je výraz, který se bude vyhledávat a který bude v případě shody nahrazen druhým. Za poslední lomítko bychom mohli ještě přidat číslo udávající maximální počet nahrazení v jedné řádce, nebo písmeno g (globální), které způsobí nahrazení všech odpovídajících řetězců.

Programy jako awk a sed jsou v Unixu již velmi dlouhou dobu. Společně s nástroji, jako je m4 (článek v minulém čísle) a make, poskytují velmi jednoduché, leč velmi účinné a hlavně standardizované prostředí pro tvorbu složitějších aplikací pouze prostředky systému. V dalším dílu bychom mohli právě nabyté znalosti rozšířit a zkusit je aplikovat při automatizaci tvorby domovských stránek.

Awk

Zkratka awk vznikla složením ze tří počátečních písmen příjmení tvůrců, t.j. Aho, Weinberger, Kernighan (ano, ten Kernighan, který spolu s Ritchiem vytvořili jazyk C). Je to přímý předchůdce jazyka Perl, naplno využívá síly regulárních výrazů.

Na rozdíl od sedu, jehož skripty mohou vypadat velmi podivně a pro mnoho lidí jsou neproniknutelné, awk má syntaxi velmi podobnou jazyku C. Umožňuje definovat své vlastní funkce, vypisovat na obrazovku, psát do souborů, načítat z nich atd. Co jej však činí výjimečným, je, že awk byl navržen pro zpracování textových dat, která je možno rozdělit na záznamy (obvykle jednotlivé řádky) a pole (obvykle oddělená mezerami nebo tabulátorem). Umožňuje takový soubor kompletně přeorganizovat a je možné a účelné jej využít jako filtr mezi dvěma různými formáty.

Ukažme si skript pro konverzi souboru /etc/passwd na CSV soubor, vhodný k importu např. do OpenOffice.org např. za účelem vytvoření vnitrofiremního telefonního a mailového seznamu. Formát souboru /etc/passwd je:

uživatelské jméno:heslo:uid:gid:informace:domovský adresář:shell

Informace mají formát:

Jméno Uživatele,číslo místnosti,telefon do práce,telefon domů

Tento skript vypíše podle očekávání obsah pole s informacemi. To ovšem sotva stačí na uspokojivý telefonní seznam.

BEGIN {
  FS = ":"
}
{
  print $5
}

V seznamu budeme chtít záznamy ve formátu:

"Jméno","Telefon","e-mail"

Upravíme tedy skript takto:

BEGIN {
  domena = "@sample.org"
  FS = "[:,]"
}
{
  mail = $1 domena
  printf("\"%s\",\"%s\",\"%s\"\n",$5,$7,mail)
}

Pokud tento skript spustíme s programem awk (resp. gawk nebo mawk) pomocí příkazu

cat /etc/passwd | awk -f skript.awk

dostaneme na výstupu CSV data pro telefonní seznam.

Diskuze (0) Nahoru