Něco málo o sedu: stream editor

1. 7. 2003
Doba čtení: 8 minut

Sdílet

Má cenu se ve světě, zaplňovaném Enterprise technologiemi a jánevímčímještě, zabývat provařeným prográmkem starým jako Metuzalém? Já se domnívám, že ano, máte-li opačný názor, berte prosím tento článek jako předčasný příspěvek k okurkové sezóně.

Motto:

We're peering into the origin of Unix here. I knew people at Bell Labs though I never worked there myself. The late Lee E. McMahon, the original author of ‚sed‘, was a fellow student at Rice University in the early 1970s before he went off to Bell Labs to write ‚sed‘.

Aha! I knew it! Having such a clumsy syntax was necessarily the result of some student project :)

    [ mail.gnu.org, archiv konference autoconf-patches ]

Co je to sed

Program sed (stream editor) je určen pro dávkové zpracování textů. Je větší než grep, a podobně jako u grepu, pro využití sedu musíme vědět něco o regulárních výrazech a o programování v shellu. V tomto článku se věnuji klasickému starému sedu, ačkoliv se zmíním i o některých rozšířeních Gnu.

Použití sedu vypadá takto

sed [-n] [-e script] ... [-f script_file] ... [soubor ...]

nebo v koloně

cat "soubor" | sed [-n] [-e script] ... [-f script_file]

Sed čte ze souboru řádku po řádce, přičemž obyčejně funguje v následujícím cy­klu:

  1. přečte řádku a interně si ji očísluje
  2. řádku vloží do svého pracovního prostoru
  3. na obsah pracovního prostoru postupně aplikuje sedscript, tj. posloupnost sedovských příkazů
  4. na závěr cyklu obsah pracovního prostoru pošle na standardní výstup

a tak dále až do konce souboru.

Pracovní prostor (pattern space, PS) je kus paměti, který může obsahovat jednu nebo více řádek. On a jeho bráška paměťový prostor (hold space, HS) tvoří jediné dvě proměnné, do kterých můžeme něco uložit. Implicitní výstup podle bodu d) lze potlačit parametrem -n

Posloupnost sedovských příkazů se zadává přímo z řádky pomocí -e nebo se čte ze souboru pomocí -f . Obě volby se mohou opakovat a míchat mezi sebou, rozhodující je pořadí na řádce.

Pomocí obou způsobů je zadána posloupnost příkazů, kterou dále nazývám sedscript. Maximální počet příkazů sedscriptu býval sto. Také je možné volby -e -f vynechat úplně, potom sed jako své příkazy intepretuje první argument. Jako obvykle, pokud sed nedostane jméno textového souboru, čeká na data ze standardního vstupu.

Příklad:
sed ' ' text dělá totéž, co cat text.

Dále předpokládejme ukázkový desetiřádkový textový soubor text obsahující:

radka 1
radka 2 start
radka 3
radka 4 stop
radka 5
radka 6 start-stop
radka 7
radka 8
radka 9
radka 10

V příkladech se objeví příkaz sedu p, tj. tisk na standardní výstup.

Adresování řádků

Osamělý sedovský příkaz zareaguje na každou řádku, která přijde. Platnost sedovského příkazu lze omezit jednou adresou nebo rozsahem dvou adres oddělených čárkou.

Adresy jsou dvojího druhu:

  1. číslo řádku, speciálně $ znamená poslední řádku vstupu (pozor na shellovskou expanzi)
  2. regulární výraz (RE)
  3. Regulární výrazy se zadávají uzavřené mezi lomítka, např. /^Aug.sshd.Fa­iled/

Eskejpování lomítek uvnitř RE se lze vyhnout alternativním zápisem:

\x^Aug.*sshd.*Failedx

kde x může být libovolný nekontrolní znak.

Pokud je před příkazem uvedena jedna adresa, bude příkaz aplikován na každou vyhovující řádku.

V případě dvou adres příkaz funguje na rozmezí (blok) řádek od,do včetně. Platnost adresy nebo rozsahu adres lze obrátit připojením vykřičníku. Vykřičník můžeme v popisu adresy umístit pouze na úplný konec, takže zápis sed -n '/start/!,10p' text je špatně.

Posledním kouzlem s adresami jsou složené závorky. Díky nim lze pro danou adresu sdružit více příkazů do bloku.

#!/usr/bin/sh
sed -n '/start/{
p
/stop/{
p
}
}
'
text
$ ./s.sh
radka 2 start
radka 6 start-stop
radka 6 start-stop

Otvírací závorka musí ležet na konci řádky a uzavírací závorka na samostatné řádce. Na příkladu vidíme, že bloky příkazů lze vnořovat.

Přehled příkazů

Nejprve si uvedeme přehled všech příkazů. Není jich mnoho, ale protože některé z nich mají vedlejší efekty, skládání sedovského skriptu připomíná hru Tetris.

Tabulka č. 447
#n na první řádce scriptu znamená totéž co parametr -n
# je komentář
[1adresa]q ukonči se (implicitní výstup se provede)
[1adresa|rozsah]p vytiskni obsah pracovního prostoru plus znak nové řádky
[1adresa]= vytiskni číslo aktuální řádky a odřádkuj
[1adresa|rozsah]y/ab­c/xyz/ zaměň znaky pracovního prostoru
[1adresa|rozsah]s/vzor/n­áhrada/ příznaknahraď v pracovním prostoru
[1adresa|rozsah]d smaž pracovní prostor, pokračuj další řádkou od začátku sedskriptu
[1adresa|rozsah]l vytiskni obsah pracovního prostoru a místo speciálních znaků tiskni jejich ascii kód
[1adresa|rozsah]n do pracovního prostoru načti další řádku, předchozí obsah zapomeň
[1adresa]a\ vytiskni za append
[1adresa]i\ vytiskni před insert
[1adresa|rozsah]c\ změň, vytiskni a začni nový cyklus change
[1adresa]rsoubor vytiskni obsah souboru
[1adresa|rozsah]wsou­bor zapiš pracovní prostor do souboru
[1adresa|rozsah]N do pracovního prostoru přidej znak \n plus další řádku ze vstupu, když žádná další řádka není k dispozici, skonči
[1adresa|rozsah]D v pracovním prostoru odmaž jednu řádku a skoč na začátek sedskriptu, pokud je pracovní prostor prázdný, přečti do něj další řádku
[1adresa|rozsah]P z pracovního prostoru vytiskni jednu řádku
[1adresa|rozsah]h ulož obsah pracovního prostoru do paměťového prostoru
[1adresa|rozsah]H do paměťového prostoru připoj znak \n plus obsah pracovního prostoru
[1adresa|rozsah]g ulož obsah paměťového prostoru do pracovního prostoru
[1adresa|rozsah]G do pracovního prostoru připoj znak \n plus obsah paměťového prostoru
[1adresa|rozsah]x vyměň mezi sebou obsahy pracovního a paměťového prostoru
:návěští je návěští
[1adresa|rozsah]bná­věští skoč na návěští
[1adresa|rozsah]tná­věští podmíněný skok, pokud byla úspěšná poslední náhrada pomocí s příkazu

Příkazy mohou být uvedeny buď zvlášť, na samostatných řádkách, nebo mohou být odděleny středníkem. Středníkem nelze oddělovat

příkazy :,b,t pracující s návěštími.

Příkaz [1adresa]q

Sed sice hned skončí, ale bez -n volby se obsah pracovního prostoru s koncem skriptu vytiskne.

Příkaz [1adresa|rozsah]p

Používá se většinou spolu s volbou -n .

$ sed -n '/stop/p' text
radka 4 stop
radka 6 start-stop

Příkaz =

Vytiskne obsah čítače řádek. Čísla se tisknou na samostatné řádky a počítají se dohromady přes všechny zpracovávané soubory. Podobně dohromady pro všechen vstup funguje i adresa poslední řádky $.

$ sed -n '$='text text
20

Příkaz [1adresa|rozsah]y/ab­c/xyz/

Slabší varianta unixovského tr. Neumí rozsahy ani třídy, všechny znaky je nutné vypsat.

Příkaz [1adresa|rozsah]s/vzor/n­áhrada/příznak

Nahrazování v pracovním prostoru. Vzor je regulární výraz, ve kterém se mohou používat sdružovací \( ) a intervalové závorky \{n,m\}. Plus a otazník jsou obyčejné znaky. Místo obyčejného lomítka lze jako oddělovač za s použít libovolný nekontrolní znak, který se ale musí uvnitř RE eskejpovat. V náhradě mají kromě zpětného lomítka speciální význam také:

& … značí řetězec odchycený vzorem

\n … značí podřetězec odchycený ve vzoru pomocí sdružovacích \( ) závorek

Zpětná reference \n tvoří jednu z hlavních předností sedu. Nemá ji ani klasické awk, tj. bez funkce gensub. Ve vzoru lze používat sekvenci \n pro znak nového řádku. Příznaky mohou být číslo – reaguje pouze na n-tý výskyt vzoru, p jako print, g jako global, nebo w file pro zápis do souboru.

Příkaz [1adresa|rozsah]d

Smaže pracovní prostor, ignoruje zbytek sedscriptu a zahájí nový cyklus, tj. načtení další řádky vstupu podle bodu a).

Příkaz [1adresa|rozsah]l

Vytiskne obsah pracovního prostoru a místo speciálních znaků tiskne jejich ascii kód.

Příkaz [1adresa|rozsah]n

Podle volby -n obsah pracovního prostoru buď vytiskne, nebo ne. Poté do pracovního prostoru načte další řádku a současně zvýší o jedničku čítač řádek (=). Pokračuje v provádění sedscriptu.

$ sed -n -e ‚n;p‘ text

Tiskne jen sudé řádky.

Příkaz [1adresa]a\

append text

Text se pro daný řádek přidá až za sedovský výstup dané řádky.

Příkaz [1adresa]i\

insert test

Text se pro daný řádek vloží do sedovského výstupu.

Příkaz [1adresa|rozsah]c\

change text

Pro adresu nebo rozsah adres vytiskne „change text“ , ignoruje následující příkazy sedscriptu a pokračuje novým cyklem.

Příkaz [1adresa]r soubor

Poté, co načte a zpracuje adresovanou řádku, vytiskne obsah souboru. Obsah souboru se neukládá do paměťového prostoru a tiskne se i při volbě -n.

Příkaz [1adresa|rozsah]w soubor

Pro dané adresy zapiš pracovní prostor do souboru. Soubor je založen/přepsán při startu sedu, poté se do něj až do zpracování všech datových souborů připisuje.

Příklad

sed -n -e ‚s/^[^0–9]\([0–9]).*/\1/ ;w soubor‘ text text

V aktuálním adresáři se vytvoří soubor obsahující dvacet řádků s čísly 1,2,…,10,1,2,3,…,10

Příkaz [1adresa|rozsah]N

Do pracovního prostoru přidej znak \n plus další řádku ze vstupu. Pokud žádná další řádka není k dispozici, skonči ihned. Často se používá ve tvaru $!N , tj. připoj další řádek, jen pokud nejsme na posledním řádku.


Příkaz [1adresa|rozsah]D

V pracovním prostoru odmaž jednu řádku odleva až do prvního výskytu \n včetně a skoč na začátek sedskriptu. Pokud je pracovní prostor prázdný, přečti do něj další řádku ze vstupu.


Příkaz [1adresa|rozsah]P

Z pracovního prostoru vytiskni jednu řádku, tj. všechno zleva až do znaku \n .


Příkaz [1adresa|rozsah]h

Ulož obsah pracovního prostoru do paměťového prostoru. Paměťový prostor byl původně určen pro uchovávání několika málo řádek a jeho maximální velikost je třeba vyhledat v manuálových stránkách (hpux sed 8192 bytů). Gnu implementace toto omezení nemá.


Příkaz [1adresa|rozsah]H

Na konec paměťového prostoru připoj znak \n plus obsah pracovního prostoru.


Příkaz [1adresa|rozsah]g

Ulož obsah paměťového prostoru do pracovního prostoru (protějšek malého h).

Příkaz [1adresa|rozsah]G

Na konec pracovního prostoru připoj znak \n plus obsah paměťového prostoru (protějšek velkého H).

Příkaz [1adresa|rozsah]x

Vyměň mezi sebou obsahy pracovního a paměťového prostoru.

Příkaz :návěští

Jako označení návěští se považují znaky za dvojtečkou do konce řádky. V jednořádkových sedovských skriptech je nutné příkaz uvést jako samostatnou -e ‘: navesti‘ volbu.

Příkaz [1adresa|rozsah]bná­věští

Skoč na návěští. Pokud návěští není uvedeno, skáče se na konec sedscriptu.

Příkaz [1adresa|rozsah]tná­věští

Podmíněný skok, pokud v právě zpracovávaném řádku došlo od předchozího použití t příkazu k alespoň jedné úspěšné náhradě pomocí s substituce. Jedná-li se o první použítí t příkazu pro daný řádek, počítají se s příkazy od začátku cyklu.

bitcoin_skoleni

Bez uvedeného návěští se skáče na konec sedscriptu.

Příště se podíváme na příklady použití.

Autor článku