Programujeme v sede

Sed

sed je skvelý nástroj na nahrádzanie výskytov reťazcov v textoch, ale aj pre mnoho iných, nečakaných manipulácií s textovými súbormi. Jeden z najprehľadnejších návodov nájdete na http://www.grymoire.com/Unix/Sed.html. Samozrejme, užitočná je aj infotex stránka v dokumentácii (info sed)

Príkaz pre nahradenie

Najčastejšie používaným príkazom je s, teda substitute. Má minimálne dva parametre: výraz, ktorý chceme nahradiť a výraz, ktorým nahradíme nájdený text. Školský príklad:

echo Milujem Windows | sed 's/Windows/Linux/'

Výstupom je Milujem Linux.

Nástroj sed podporuje aj tradičné špeciálne znaky typu \n (nový riadok), \t (tabulátor) atď.

echo Ahoj svet | sed 's/ /\n/'

Výstupom je

Ahoj
svet

Pozor na to, že sed nahrádza štandardne len prvý výskyt na riadku. Ak chceme vykonať globálne nahradenie všetkých výskytov, použime príznak g za nahradením

echo John Paul Ringo George | sed 's/ /\n/g'

Výstupom je

John
Paul
Ringo
George

Iný príklad

echo Terry Jones, Terry Gilliam | sed 's/Terry/T./g'

Výstupom je

T. Jones, T. Gilliam

Niekedy potrebujeme nahradiť len konkrétny, napr. druhý výskyt. Namiesto príznaku g môžeme použiť poradové číslo výskytu na riadku. V príklade vymažeme druhého Terryho:

echo Terry Jones, Terry Gilliam | sed 's/Terry/T./2' 

Výstup:

Terry Jones, T. Gilliam

Ak chceme vymazať výskyt slova z riadku, stačí nahradiť text prázdnym reťazcom a použiť globálne nahrádzanie

echo Terry Jones, Terry Gilliam | sed 's/Terry//g'  

Výstupom je

Jones,  Gilliam

Ak prekážajú medzery, stačí poupraviť hľadaný výraz (dodajme medzeru):

echo Terry Jones, Terry Gilliam | sed 's/Terry //g'  

Niekedy chceme nájsť výraz a v nahradení ho použiť tak ako je, iba s nejakou predponou, či príponou. Ampersand & vo výraze nahradenia obsahuje nájdený výraz. Obaľme všetkých Terryov hviezdičkami:

echo Terry Jones, Terry Gilliam | sed 's/Terry/*&*/g'  

Vybrané výrazy môžeme uzavrieť do zátvoriek, čím vyznačíme skupiny a potom na ne vo vyhľadávacom výraze. Ak chceme z riadka označujúceho Java interfejs vyseknúť len jeho názov, môžeme ísť na to nasledovne:

echo 'public interface MyComparator {' | sed 's/public interface \([^ ]*\).*/\1/'

Nájsť všetky interfejsy je potom ľahé

find / -name *.java -exec sed -n 's/public interface \([^ ]*\).*/\1/p' {} \; 2> /dev/null

Analogicky vieme nahradiť cut. Ak chceme vypísať domovské adresáre používateľov, tu je postupnosť krokov. Najprv zadefinujme premennú pre sprehľadnenie regexpu:

E="\([^:]*\)"

Potom ju radostne použime vo výraze, pričom využijeme shellovskú expanziu

sed 's/'$E:$E:$E:$E:$E:$E:.*'/\6/g' /etc/passwd    

Príkaz q (quit) a rozsahy riadkov

Nástroj sed môžeme použiť ako lacnú náhradu headu. Ďalším užitočným príkazom je q (quit).

Jednoduché použitie načíta prvý riadok zo súboru a skončí beh sedu

sed q /etc/passwd

Väčšia zábava bude s použitím rozsahov. Každý príkaz môže mať rozsah, teda špecifikáciu riadkov, na ktoré sa použije. Veľmi často sa používa rozsah v podobe čísiel riadkov: Prvé tri súboru (teda ekvivalent head -n3) vypíšeme

sed 3q /etc/passwd

Priebeh je nasledovný: vo chvíli, keď sed naďabí na tretí riadok, vykoná uvedený príkaz – v našom prípade skončí.

Príkaz p (print)

V štandardnom režime funguje sed tak, že každý načítaný riadok automaticky vypisuje bez ohľadu na to, či sa naň aplikoval nejaký príkaz alebo nie. Niekedy však chceme tlačiť len riadky, na ktoré sa príkaz skutočne použil.

Najjednoduchšie použitie príkazu print zduplikuje každý riadok:

echo Hello World | sed p

Oveľa častejšie sa p používa v kombinácii s prepínačom -n. Ten spôsobí, že sed nebude automaticky vypisovať žiadne riadky, ale vypíše tie, na ktoré sa aplikuje p.

Tretí riadok vieme vypísať pomocou

sed -n 3p /etc/passwd

Podobne môžeme iným spôsobom napodobniť head

sed -n 1,10p /etc/passwd

Ak chceme použiť rozsah ,,od piateho riadku až do konca”, môžeme pre posledný riadok použiť zástupný znak $ (keďže je to špeciálny znak shellu, obaľme príkaz do apostrofov):

 sed -n '5,$p' /etc/passwd

Možno vám napadne, že či sa nedá napodobniť aj tail. Na to však potrebujeme kombináciu viacerých príkazov shellu. V príklade vypíšeme posledných 10 riadkov súboru:

 L=$(wc -l < /etc/passwd); sed -n $((L-9))',$p' /etc/passwd

Do premennej L si poznamenáme počet riadkov súboru, v aritmetickom prostredí odčítame od počtu riadkov deväť, čím získame číslo desiateho riadku od konca a vypíšeme riadky medzi L a koncom súboru.

,,Sprehľadniť” skript možno ešte dodatočnou premennou s názvom súboru

F=/etc/passwd; L=$(wc -l < $F); sed -n $((L-9))',$p' $F

Príkaz print v náhrade grepu

Namiesto rozsahu riadkov môžeme použiť príkaz na riadky, ktoré spĺňajú regulárny výraz a tým nahradiť grep

Vypísať riadok z /etc/passwd, ktorý obsahuje informácie o rootovi môžeme:

sed -n /root/p /etc/passwd

Nezabudnime na parameter -n, v opačnom prípade sa vypíšú všetky riadky, ale riadok s rootom dvakrát.

Ak chceme vypísať všetkých používateľov, ktorí sa nemôžu prihlásiť (majú shell /bin/false), musíme escapenúť špeciálny znak lomky (pretože tá oddeľuje parametre príkazu s) a keďže samotná lomka je špeciálny znak v shelli, uzavrime príkaz do apostrofov:

sed -n '/\/bin\/false/p' /etc/passwd

Tento štýl lomiek sa familiárne nazýva plánkový plot a je pomerne neprehľadný. Našťastie sed umožňuje nastaviť pre úlohu oddeľovača ľubovoľný znak. Ak použijeme napríklad rúru, príkaz sa sprehľadní:

sed -n '|/bin/false|p' /etc/passwd

Mazanie (delete) pomocou d

Na mazanie riadkov zo vstupu slúži príkaz d. Filozofia je jasná: stačí uviesť rozsah riadkov, na ktoré sa d použije.

Prvých troch používateľov z /etc/passwd zmažeme

sed 1,3d /etc/passwd

Alternatívne môžeme mazať pomocou vzorky a regulárneho výrazu. Používateľa novotnyr zmažeme:

sed '/^novotnyr/d' /etc/passwd

Regulárny výraz začínajúcu zobákom znamená ukotvenie k začiatku riadku.

Vkladanie riadkov (insert) pred výraz pomocou i

Príkaz i vloží riadok pred aktuálny riadok. Ak máme zdrojový súbor v Jave a pred každý začiatok deklarácie triedy chceme vložiť komentár z niekoľkých mriež, vieme na to presne použiť tento príkaz.

Komentár vygenerujeme napr. týmto one-linerom

unset COMMENT; for i in $(seq 40);do COMMENT=$COMMENT#; done; COMMENT='/*'$COMMENT'*/'

Nahradenie v sede:

sed /class/i$COMMENT HelloWorld.java

Výsledkom bude súbor s riadkami, kde pred triedou bude ilustratívna čiara

#############################
public class HelloWorld {   

Vkladanie riadkov (append) pred výraz pomocou a

Analogicky k insertu funguje append, ktorý však pridáva za nájdený riadok.

Zmena riadkov (change) pred výraz pomocou c

Príkaz c zamieňa kompletné riadky novým obsahom. Čisto akademický príklad vygeneruje na každý riadok samostatné slovo a následne každý tretí riadok nahradí reťazcom TRETI

echo 'Hello World How Are You?' | tr ' ' '\n' | sed '1~3c TRETI!'

Využívame tu špeciálny rozsah riadkov s krokom: 1~3 znamená ,,počnúc prvým riadkom aplikuj príkaz na každý tretí riadok”, teda znamená to rozsah 1, 4, 7…

Číslovanie riadkov (príkaz =)

Očíslovať riadky môžeme pomocou =, s drobným nedostatkom: čísla sa vypisujú na samostatné riadky.

Napr. je jednoduché nasimulovať wc -l. Stačí zobrať za rozsah posledný riadok ($), a zakázať automatický výpis riadkov a explicitne vypísať číslo posledného riadka.

sed -n $= /etc/passwd

Príkaz N (pridaj ďalší riadok k aktuálnemu)

Ak chceme mať čísla riadkov pohromade s riadkami, je to o niečo zložitejšie. Príkaz N pridá k aktuálnemu riadku so vzorkou znak oddeľovača riadka a dolepí zaň obsah nasledovného riadka. Filozofia bude nasledovná: v prvom behu sedu vygenerujeme čísla riadkov a obsahy a v ďalšej rúre vezmeme riadok, prilepíme k nemu znak n a nasledovný riadok (pomocou N). Teraz stačí nahradiť oddeľovač riadkov tabulátorom a máme to.

Viacero príkazov v sede vieme veselo oddeľovať bodkočiarkou

sed = /etc/passwd | sed 'N;s/\n/\t/' 

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *