Něco málo o sedu: vychytávky a šílenosti

15. 7. 2003
Doba čtení: 4 minuty

Sdílet

Dnes naše povídání o Sedu zakončíme. Podíváme se ještě na některé složitější skripty a dojde i na vychytávky a šílenosti - např. na problém hanojských věží a zejména pak na kalkulačku s volitelnou přesností a bází.

Trable s prázdným vzorem.

Není-li zadán vzor, sed použije naposledy použitý regulární výraz. No jo, jasně … jenže který ?

$ cat s.sed
/X/
{
:a
p
i\
*************

s///p
i\
+++++++++++++
s/Y/X/p
/Y/ba
}
$ ../arch/sed -V
GNU sed version 3.02
$ echo "XYY" | ../arch/sed -n -f s.sed
XYY # tisk

*************
YY # místo prázdného vzoru byl použit X
+++++++++++++
XY # náhrada Y --->> X ; následuje skok
XY # tisk
*************

Y # místo prázdného vzoru sed opět použil X
+++++++++++++
X # nakonec příkaz s změní Y na X a následující skok se neprovede

Vidíme, že výraz s///p zafungoval pokaždé jako s/X//p, ačkoliv před druhým průchodem sed skákal z řádku /Y/ba. Při prvním průchodu s///p sed nejen použije předchozí regulární výraz, ale použije ho už napořád. Předchozí výraz nemusí být ani proveden, může ležet např. na neplatné adrese, přesto bude použit a pak se s///p bude chovat jen podle něj.

Druhá varianta je implementace, která používá RE dynamicky. V našem příkladě by druhý průchod proběhl s/Y//p, červená řádka by obsahovala X a poslední řádka výstupu by chyběla vůbec.

Testované Gnu sedy do 3.02 včetně a také sedy přítomné v HP-UX 11.11 a v SunOS 5.8 se chovají stejně, „staticky“. Jak je na tom BSD sed nevím, ale dynamické chování používají nejnovější Gnu sedy – čtyřkové verze.

Mimo toho, pokud Gnu sedu 4.0.5 a 4.0.7 nastavíme proměnnou POSIXLY_CORRECT, interpretuje prázdný vzor doslova jako prázdný vzor.

$ echo "XYY" | ( unset POSIXLY_CORRECT ; ./bin/sed-4.0.7 -n -e '/Y/p' -e 's//a/gp' )
XYY
Xaa
$ echo "XYY" | ( POSIXLY_CORRECT=1 ./bin/sed-4.0.7 -n -e '/Y/p' -e 's//a/gp' )
XYY
aXaYaYa

Z uvedených příkladů plyne, že trvám-li na přenositelnosti, nejjistější je prázdný vzor nepoužívat vůbec.

Testy a skoky

Pomocí příkazu t test testujeme úspěšnost substituce od posledního předchozího t příkazu v aktuálním cyklu, přinejhorším tedy od startu cyklu. Prošel-li program mezitím přes víc substitučních příkazů, stačí, aby k náhradě došlo v jednom z nich. Při mazání paměťového prostoru uvnitř dlouhého skriptu tak můžeme narazit na „zbytečný“ skok jen kvůli vyčištění příznaku provedené substituce.

#!/usr/bin/sed -f
# vyhazuje duplicitní položky
# PATH=`echo $PATH | script.sed`
# přidám : na začátek a na konec
s/^\(.*)$/:\1:/

ta
:a

# nesousedící položky
s/\(:[^:][^:]*:)\(.*)\1/\1\2:/g
# sousední položky
s/\(:[^:][^:]*)\1:/\1:/g
ta
# vícenásobné :
s/::*/:/g
# krajní :
s/^:\(.*)/\1/
s/\(.*):$/\1/
# p
# --- end ---

Jednořádkové skripty a středník

V jednořádkových skriptech často oddělujeme příkazy pomocí středníku. Nelze to ale dělat vždy. Návěští, skok, podmíněný skok a složenou závorku ukončující blok příkazů musíme zapsat samostatně.

Příklad – za každým zavináčem @ odřádkovat, obyčejný sed

sed -n -e 'h' -e ':a' -e 's/@.*/@/p; g; s/[^@]*@//' -e 'h;ta' -e 'p'

Vychytávky a šílenosti

Sedovské skripty se nečtou dobře. U těch jednodušších ještě lze většinou vysledovat, z jakých stavebních kamenů byly složeny. Vezměme skript:

# odstraňuje mezery všude na řádce vyjma
# 'sekvencí v uvozovkách' předpokládá, že jednoduché
# uvozovky se na řádce vyskytují v párech, nebo vůbec ne

/^\([^']*'[^']*')*[^']* [^']*/{
: loop
h
s/^\([^']*'[^']*')*\([^']* [^']*).*/\2/
s/  *//g
G
s/\(.*)\n\(\([^']*'[^']*')*)[^']* [^']*\(.*)/\2\1\4/
/^\([^']*'[^']*')*\([^']* [^']*)/b loop
}
#---end of script---

Jestliže se nezalekneme regulárních výrazů, zjistíme, že se jedná o v minulém díle zmiňovanou transformaci výseku řádky hsGs. Transformace (vynechávání mezer), je pouze zabalená ve smyčce sestavené tak, aby od konce postupně vysekávala kusy řádku nechráněné uvozovkami.

Naproti tomu existují skripty svědčící o důvtipu a velké inteligenci jejich tvůrců a snaha zjistit jak vlastně fungují, vyžaduje značnou dávku odvahy. Jako ukázky uveďme problém hanojských věží a zejména kalkulačku s volitelnou přesností a bází. Zmíněná kalkulačka je dílem Grega Ubbena a naleznete ji v sadě testů u zdrojových souborů Gnu sedu. Přiznávám, že jsem zanechal pokusů zjistit, jak dc.sed vlastně funguje. Jeho analýzu proto přenechávám laskavému čtenáři.

Sed is not dead

Vývojáři Gnu sed udržují a vylepšují. Horší zpráva je, že díky tomu Gnu sed postupně kyne. Rozdílů mezi Gnu sedem a sedem z bsd i z komerčních unixů přibývá a to pro další nové příkazy zbývá ještě mnoho nevyužitých písmenek abecedy.

Datum   Velikost    Verze
06/01/93    93,301      sed-1.18.tar.gz
05/13/94    114,600     sed-2.05.tar.gz
08/02/98    264,236     sed-3.02.tar.gz
04/11/03    693,903     sed-4.0.7.tar.gz

Předmětem rozsáhlé debaty se stala otázka, jestli je to dobře. Maintaineři dělají svou práci dobrovolně a používat poslední vymoženosti koneckonců nikdo nikoho nenutí. Kdo požaduje maximální kompatibilitu, nechť si nastaví proměnnou POSIXLY_CORRECT a tím nové vlastnosti zakáže. Mezi speciality Gnu 4.xx sedu patří např. rozšířené možnosti adresování, příkaz e volající během cyklu externí program, čtení a zápis z pracovního prostoru do souboru po jednotlivých řádkách a další. Ne všechny novinky se setkaly s kladným ohlasem a z příštích verzích Gnu sedu plánuje vývojář Paolo Bonzini některé příkazy zase odstranit.

Závěr

Přestože se sed během let stal samozřejmou součástí unixu, mnozí uživatelé používají ze sedu jediný příkaz, pokud vůbec. Vzhledem k jeho omezením a přítomnosti mocnějších nástrojů se nelze příliš divit. Bombastický rozvoj tenhle prográmek asi nečeká, ale v /usr/bin může spokojeně vegetovat dalších třicet let. Přejme mu to.

Knihy, odkazy, tutoriály

Dougherty Dale, Robbins Arnold: Sed & Awk
Oreilly & Associates, ISBN: 1–56592–225–5

Sedovská houmpejdž na SourceForge, zejména
sed.sourcefor­ge.net
sed.sourcefor­ge.net/grabbag

ict ve školství 24

Popis originálního sedu přímo od jeho tvůrce Lee E. McMahona
www.cs.ucf.edu/cou­rses/cop3346/U­NIX/sed.pdf

Mailová konference na Yahoo
groups.yahoo.com/grou­p/sed-users/

Autor článku