Hlavní navigace

Něco málo o sedu: příklady použití

Jan Žalman 8. 7. 2003

Sed je nejen mocný, ale podle ohlasů na první díl seriálu i velice populární nástroj. Dnes budeme v povídání o něm pokračovat konkrétními příklady použití - podíváme se na jednoduché, až triviální skripty, ale nakousneme i ty složitější.

Sám pro sebe jsem si rozdělil sedovské skripty do tří kategorií:

  • triviality, často jednopříkazové ‚skripty‘, typicky příkaz s
  • složitější skripty s příkazy pro práci s pracovním a paměťovým prostorem (h, H, g, G, x) a skripty, které kromě předchozího obsahují skoky a cykly, příkazy N;P;D a víc řádků v pracovním prostoru
  • vychytávky a šílenosti

Triviality ne vždy triviální

Trable s jednoduchými skripty většinou plynou z neznalosti regulárních výrazů.

Problémy mohou plynout i z drobných rozdílů mezi různými verzemi sedu. Kromě obligátního odkazu na manuálové stránky a na stránku sedovských one-linerů (http://sed.sou­rceforge.net/sed1li­ne.txt), dodejme několik tipů:

Jemnosti adresování

Jak funguje rozsah /RE1/RE2/příkaz?

Sed začne aplikovat příkaz na řádce vyhovující RE1 a na řádkách následujících, až do řádky, na které najde RE2 včetně. Poté opět nedělá nic, až do dalšího výskytu RE1 atd…

$ sed -n '/start/,/stop/p' text
radka 2 start
radka 3
radka 4 stop
radka 6 start-stop
radka 7
radka 8
radka 9
radka 10

Proč výpis neskončil řádkou 6? Pokud sed najde RE1, hledá RE2 až odnásledující řádky (na rozdíl od awk).

Dále by nás nemělo zaskočit, že zadáme-li rozsah řádek číselně od větší než do, provede se příkaz také a to pro řádku od.

5,6 p  tiskne řádky 5 a 6
5,5 p  tiskne řádku 5
5,3 p  tiskne řádku 5 (!)

Vhodné uvozovky

Nejlépe jednoduché, dvojité použijme pouze pokud potřebujeme do skriptu propašovat shellovou proměnnou.

Příklad chyby: chceme vytisknout poslední řádku souboru

$ sed -n "$p" text

Rozdíly v chování regulárních výrazů

Původní sed nedovoluje použít \n v nahrazovací části s příkazu. Také podporuje pouze BRE, basic regular expressions, viz man 5 regexp. Nepodporuje plus, otazník a svislítko.

Gnu sed umí \n, \t, a čtyřkové verze s volbou -r používají ERE, ansi sekvence a \osmičkové\de­cimální\hexa sekvence. Nedokumentovaná volba -r zapínající ERE existuje už v sedu 3.02.

Příklad: chci nový řádek za každým výskytem znaku @
pouze gnu sed 4.xx: sed -e ‚s/@/@\n/g‘

Odlišné chování příkazů s a N

Dojde-li k náhradě s/vzor/obraz/p, v kterém případě se tiskne a kdy ne?

  • některé implementace tisknou pattern space pouze při sed -n (jinak spoléhají se na defaultní výstup)
  • všechny Gnu sedy tisknou s///p vždy

Od verze Gnu sed v3.02.80 a vyšší příkaz N na poslední řádce vytiskne pracovní prostor. Původní sed tiše zhasl, jak to popisuje i kniha Sed & Awk,

$ echo "jedna radka" | sed  -e 'N'
$

zatímco modernější vypíší

$
echo "jedna radka" | sed  -e 'N'
jedna radka
$

Oprava tradičních skriptů: místo starého „N“ vložit sekvenci"$d;N"

Co připojím na konec, je až na konci

Pro příkazy a (append), c (change), ale také r soubor jde výstup mimo pracovní prostor a připojuje se až za výstup sedu pro zpracovávaný cyklus.

Příkaz i (insert) tiskne svůj výstup i uprostřed zpracování aktuálního cyklu, tiskne prostě tam, kde ve skriptu je.

Není na světě jenom sed …

Místo složitého regexpu nebo sedscriptu může být pohodlnější použít pajpu a kombinovat s prográmky jako tr, cut, tac …, nebo využít výrazy shellu jako je ${foo%%neco}.

Chci vynechat čtyři poslední řádky

tac | sed '1,4d' | tac

(no jistě, tady by si vystačil tail, je to jenom příklad)

Složitější skripty, s pokročilejšími příkazy nebo cykly

Pokročilejší skripty využívají schopnost pracovního prostoru načíst do sebe víc než jednu řádku. Pracovní a paměťový prostor se používá jako roura.

Porovnávání s předchozí řádkou

Jednoduchý příklad využití paměťového prostoru je sedovská emulace příkazu uniq.

sed 'x;G;/^\(.*\)\n\1$/d;g'

Porovnávání s předešlou řádkou a použití bloku umožnuje udělat akci na začátku, nebo konci výskytu sekvence řádků obsahující VZOR.

# provede něco na řádce za blokem řádek obsahujícím VZOR
/VZOR/!{
x
/VZOR/i\
AKCE - KONEC VZORu
x
}
h
#
--- end ---

Stavová informace v sedu

Obecně vzato – jakými způsoby lze v sedu uchovávat informaci „v prohledávaném textu se nacházím mezi značkami begin a end “? Následující příklady pocházejí od Grega Ubbena – cílem je vstup kopírovat na výstup vyjma řádek mezi značkami begin a end (značky leží na začátku řádky).

Metoda 1 – používá paměťový prostor

Jsem-li na řádce za begin a není-li to zrovna řádka end, v paměťovém prostoru mám schovanou značku begin.

/^end/ h
x
/^begin/{ x; d; }
x
/^begin/ h

Metoda 2 – zda jsem v bloku, mi říká pozice v programu

Kvůli zpracování vnitřku bloku se v programu nachází extra smyčka.

#n run this script using the sed -n flag
/^begin/{
p
: loop
n
/^end/!b
loop
}
p

Metoda 3 – používám rozsah adres

Pokud jde o bloky řádek, v daném případě asi nejhezčí postup.

/^begin/,/^end/{
  /^begin/b
  /^end/b
  d
}

Transformace výseku řádky „hsGs“

Stane se, že z řádky na vstupu potřebujeme transformovat jenom výsek. Originální řádku si nejprve uschováme do paměti, v pracovním prostoru si jí ořízneme a zmutujeme podle potřeby a nakonec sestavíme výsledek.

h
s/zacatek\(VZOR\)zbytek/\1/
# tranformace vzor-->cil
...
G
s/\(.*\)\n\(zacatek\)VZOR\(zbytek\)/\2\1\3/
# nyni mam   zacatekCILkonec

Podobně lze obejít fakt, že v nahrazovací části s-příkazu původního sedu nelze použít newline.

h
s/.*//
G
s/^\(\n\)puvodni radka/v nahrade pouzivam \1 jako newline/

Paměťová omezení

Originální sed omezoval objem pracovního i paměťového prostoru. Tyto proměnné byly původně určeny pro uchovávání několika málo řádek a jejich maximální velikost je třeba vyhledat v manuálových stránkách (např. 8192 bytů). Gnu implementace toto omezení nemá.

Příklad – emulace tac, výpis souboru s převráceným pořadím řádek

sed -n '1!G; h; $p'

pro velké soubory s non-gnu sedem selže.

Ve skriptech obsahující cykly se sed často nespoléhá na implicitní vstup a výstup na začáttku a na konci, ale cyklí a cyklí a mezitím čte a zapisuje si po svém.

Kolovrátek N;P;D

Zhusta používaná technika se dá nazvat cyklus N;P;D. V našem modelovém příkladě vynecháváme čtyři poslední řádky, čistě sedovsky

sed -e ':a' -e '$d;N;2,4ba' -e 'P;D'

Sed je stream editor, vstup zpracovává postupně a pouze jednou, takže netuší, kolik řádek v souboru je. Když chceme mazat čtyři poslední řádky, vytvoříme si z pracovního prostoru 4-řádkovou rouru, kterou na posledním řádku ($d) zahodíme. Do té doby (tj. od pátého řádku dál) vždy z výfuku roury vytiskeme řádek (P), z roury ho odstraníme (D) a rouře do tlamy natlačíme řádek nový (N). Na začátku skriptu si rouru musíme tiše naplnit pomocným cyklem (2,4ba).

Mazaná řádka bude vždy aspoň jedna, což plyne ze způsobu, jakým sed nakládá s rozsahem adres.

To by pro dnešek stačilo. Příště dokončíme složitější skripty a dojde i na zmíněné vychytávky a šílenosti.

Našli jste v článku chybu?

14. 7. 2003 15:31

Ludvik (neregistrovaný)

Trochu nechapu zadani, ale pokud jde o vynechani pouze druheho "sloupce" mezi carkami, ktery tam byt nemusi, tak by melo fungovat toto:

sed 's/",.*,"/","/'

Problem by bylo pouze pokud by texty v uvozovkach zacinaly nebo koncily carkou, ale jestli to jsou nejake rozumne vety, tak to asi nemuze nastat.





10. 7. 2003 14:57

Radek Vybíral (neregistrovaný)

Ten priklad byl pouze pro ilustraci, obecne tam muze byt text jakykoliv, cili se neda pouzit zadny vzor.

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Lupa.cz: Seznam mění vedení. Pavel Zima v čele končí

Seznam mění vedení. Pavel Zima v čele končí

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře

Root.cz: 250 Mbit/s po telefonní lince, když máte štěstí

250 Mbit/s po telefonní lince, když máte štěstí

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

Podnikatel.cz: Na poslední chvíli šokuje výjimkami v EET

Na poslední chvíli šokuje výjimkami v EET

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

Podnikatel.cz: Babiše přesvědčila 89letá podnikatelka?!

Babiše přesvědčila 89letá podnikatelka?!

Root.cz: Certifikáty zadarmo jsou horší než za peníze?

Certifikáty zadarmo jsou horší než za peníze?

DigiZone.cz: Rádio Šlágr má licenci pro digi vysílání

Rádio Šlágr má licenci pro digi vysílání

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Root.cz: Vypadl Google a rozbilo se toho hodně

Vypadl Google a rozbilo se toho hodně

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Měšec.cz: Air Bank zruší TOP3 garanci a zdražuje kurzy

Air Bank zruší TOP3 garanci a zdražuje kurzy

Lupa.cz: Insolvenční řízení kvůli cookies? Vítejte v ČR

Insolvenční řízení kvůli cookies? Vítejte v ČR

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

Vitalia.cz: Chtějí si léčit kvasinky. Lék je jen v Německu

Chtějí si léčit kvasinky. Lék je jen v Německu

Vitalia.cz: Mondelez stahuje rizikovou čokoládu Milka

Mondelez stahuje rizikovou čokoládu Milka

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky