#Sed

By . Latest revision .

Sed är en Stream Editor som kan söka efter, matcha, gruppera och byta ut strängar från en ström med text. Sed jobbar med options och flaggor, vilka vi ska titta mer på. Det som gör Sed till ett kraftfullare verktyg än tex Grep är möjligheten att jobba med “substitution” och att kunna editera direkt i filer, sk “inplace”. Vi blandar även in lite reguljära uttryck.

I de exempel som nu följer så används en textfil, courses.txt med innehållet:

Kenneth Lewenhagen is the teacher in the course VLinux (DV1611).
Andreas Arnesson is the teacher in the course OOPython (DV1437).
Emil Folino is the teacher in the course Webbapp (DV1609).
Mikael Roos is the teacher in the course OOPHP (DV1608).

Vi kan använda filen på följande sätt: sed OPTIONS... [SCRIPT] [INPUTFILE...]. Vill du testa själv finns filen i exempelmappen.

Några “bra-att-ha”-options och commands:

Command Beskrivning
$ sed -E Vi slipper “escapea” tecken som []{} etc. Utan -E hade vi fått använda \[\]\{\}.
$ sed OPTIONS '/<pattern>/p “p” talar om att vi vill skriva ut resultatet.
$ sed -n Vi visar enbart raden som matchar och utelämnar resten.
$ sed -ibackup Editera “inplace” och skapa en backupfil med ändelsen backup

Fler kommer dyka upp under artikelns gång.

#Versioner av sed

Sed bör vara installerat per default. Det finns dock olika versioner av programmet och den vi ska använda är GNU’s version. I skrivande stund utgår guiden från:

$ sed --version
sed (GNU sed) 4.8
...

#Matchning av sträng/siffror

Vi har textfilen att utgå ifrån.

Tips: Kopiera gärna in texten och uttrycket i https://regex101.com/ så ser du hur det fungerar.

Låt säga att vi vill ha tag i raden om kursen OOPython:

$ sed '/OOPython/p' courses.txt
Kenneth Lewenhagen is the teacher in the course VLinux (DV1611).
Andreas Arnesson is the teacher in the course OOPython (DV1437).
Andreas Arnesson is the teacher in the course OOPython (DV1437).
Emil Folino is the teacher in the course Webbapp (DV1609).
Mikael Roos is the teacher in the course OOPHP (DV1608).

Oj då, nu fick vi alla raderna samt en av dem två gånger…

Vi bryter ned händelserna:

/OOPython/ mathar all text som är exakt OOPython.
p är en flagga (kommando) som talar om att vi vill skriva ut resultatet.

Sed jobbar rad för rad och skriver automatiskt ut alla processerade rader. Vi provar lägga till flaggan -n, som stänger av det beteendet:

$ sed -n '/OOPython/p' courses.txt
Andreas Arnesson is the teacher in the course OOPython (DV1437).

Det såg bättre ut. Om vi inte hade vetat vad kursen heter då? Vi blandar in character classes. Vi provar exempelfilen igen och kursen hette något med OOP...:

$ sed -n '/OOP[a-z]\+/p' courses.txt
Andreas Arnesson is the teacher in the course OOPython (DV1437).

Snyggt! Notera att vi behövde escapa +-tecknet. För att slippa det kan vi använda ett option, -E vilket slår på extended regular expressions:

$ sed -E -n '/OOP[a-z]+/p' courses.txt
Andreas Arnesson is the teacher in the course OOPython (DV1437).

Nu händer följande:

OOP matchar alla rader med ordet OOP.
[a-z] matchar alla små bokstäver, med andra ord ython och inte HP, vilket var Mikaels kurs.
+ talar om att det ska finnas en eller flera bokstäver i följd.

Om vi hade velat ha med Mikaels kurs kan vi ändra lite vid hakparenteserna för att matcha båda:

$ sed -E -n '/OOP[a-zA-Z]+/p' courses.txt
Andreas Arnesson is the teacher in the course OOPython (DV1437).
Mikael Roos is the teacher in the course OOPHP (DV1608).

Vi har redan kikat på reguljära uttryck så vi dyker inte ner mer i det här.

#Substitution

Ett viktigt kommando i sed är “s”-kommandot (substitution). Det möjliggör att vi kan byta ut matchningen mot något annat, antingen ren text eller en hel grupp. Vi tar och kikar på hur det kan se ut. Strukturen för kommandot är:

's/regexp/replacement/flags'

Först måste vi få rätt på hur det fungerar med “substitution” och hur vi kan styra det.

$ sed -E 's/the/not a/' courses.txt
Kenneth Lewenhagen is not a teacher in the course VLinux (DV1611).
Andreas Arnesson is not a teacher in the course OOPython (DV1437).
Emil Folino is not a teacher in the course Webapp (DV1609).
Mikael Roos is not a teacher in the course OOPHP (DV1608).

Vi kan se att vi byter ut the mot not a. Det är första matchningen på varje rad som byts ut.

$ sed -E 's/the/the best/2' courses.txt
Kenneth Lewenhagen is the teacher in the best course VLinux (DV1611).
Andreas Arnesson is the teacher in the best course OOPython (DV1437).
Emil Folino is the teacher in the best course Webapp (DV1609).
Mikael Roos is the teacher in the best course OOPHP (DV1608).

Nu, tack vare flaggan /2, är det den andra matchningen på varje rad som byts ut. För att ta alla använder vi flaggan /g (global replacement):

$ sed -E 's/the/the best/g' courses.txt
Kenneth Lewenhagen is the best teacher in the best course VLinux (DV1611).
Andreas Arnesson is the best teacher in the best course OOPython (DV1437).
Emil Folino is the best teacher in the best course Webapp (DV1609).
Mikael Roos is the best teacher in the best course OOPHP (DV1608).

#Fler exempel

Vi kikar på hur vi kan ändra på informationen i filen med hjälp av substitution. Vi tänker oss att kurskoderna ska bytas ut och under tiden behöver vi ta bort de som finns. Vi byter ut dem mot “not available”:

$ sed -E -n 's/[A-Z]+[0-9]{4}/not available/p' courses.txt
Kenneth Lewenhagen is the teacher in the course VLinux (not available).
Andreas Arnesson is the teacher in the course OOPython (not available).
Emil Folino is the teacher in the course Webapp (not available).
Mikael Roos is the teacher in the course OOPHP (not available).

Vi matchar enbart kurskoden och byter ut den mot “not available”.

s/ talar om att vi vill använda substitution.
/not available/ är den andra delen av uttrycket, kallat replacement. Vi byter ut matchningen mot detta.

Än mer kraftfullt blir det om vi blandar in grupper i mixen.

#Grupper

För att markera en grupp använder vi parenteser runt matchningen, (...). Vi kan återanvända en grupp med \1, \2 etc.

Ett första exempel för att visa hur det kan fungera. Vi fångar upp för- och efternamn och återanvänder den gruppen:

$ sed -E -n 's/(^\w+\s\w+).+/\1/p' courses.txt
Kenneth Lewenhagen
Andreas Arnesson
Emil Folino
Mikael Roos

\w är detsamma som att skriva [a-zA-Z].
\s är ett mellanslag.

Låt säga att vi vill få tag på namnet på den person som har kursen Webapp tillsammans med kurskoden:

$ sed -E -n 's/(^\w+\s\w+).+Webapp.+([A-Z]{2}[0-9]{4}).+/\1 \2/p' courses.txt
Emil Folino DV1609

Nu blev det rörigt! Vi tar det bit för bit så klarnar det:

(^\w+\s\w+): Parenteserna talar om att det ska vara en grupp.
Insättningstecknet ^ (caret, morot) markerar början på raden.
Sedan följer \w som fångar alla bokstäver följt av ett plus (+) då vi vill att det ska upprepas minst en gång. Sedan kommer ett mellanslag (\s) följt av en \w till.
Nästa plustecken tar alla bokstäver fram till något annat dyker upp, som till exempel ett mellanslag. Detta blir grupp 1 (namnet).
.*Webapp.*: Konstruktionen .* matchar vilket tecken som helst, noll eller flera gånger fram till ordet Webapp. Sedan tar vi allt som kommer i vår väg igen.
([A-Z]{2}[0-9]{4}).*: Vi vet hur en kurskod ser ut så vi stannar inte förrän vi kommer till den andra gruppen. Kurskoden är två stora bokstäver följt av 4 siffror. Måsvingarna, {2}, talar om att det som sker i karaktärsklassen ska matchas 2 gånger följt av 4 siffror. Där stänger vi gruppen och plockar resten av raden med .*.
/\1 \2/: Den andra delen av uttrycket är delen som talar om vad som ska ersätta matchningen. Nu har vi ju fångat upp de grupper som vi vill återanvända så vi petar in dem där.

#Inplace

Om vi till exempel skulle ha en stor fil med massa text, kanske en scriptfil och vi vill ta bort alla semikolon för vi har uppdaterat kodstandarden till senaste eslint, kan vi ge oss på “inplace”-editering. Man skickar då in ett “pattern” rätt in i en fil och applicerar det på den. Det kan vara oerhört lurigt då man inte alltid vet hur filen ser ut eller om man inte testat sitt regex ordentligt. För att vara på den säkra sidan kan vi ta för vana att vi alltid tar en backup utan filen vi editerar. Så här gör vi:

Jag vill byta ut läraren “Andreas Arnesson” för kursen OOPython då “Marie Grahn” ska ta över den. Om man är lite våghalsig kör man kommandot rakt av:

$ sed -E -i 's/Andreas Arnesson/Marie Grahn/' courses.txt
$ cat courses.txt
Kenneth Lewenhagen is the teacher in the course VLinux (DV1611).
Marie Grahn is the teacher in the course OOPython (DV1437).
Emil Folino is the teacher in the course Webapp (DV1609).
Mikael Roos is the teacher in the course OOPHP (DV1608).

Det var kanske inte det mest farliga eller avancerade vi kunde göra men det hade vart bättre att vara på den säkra sidan:

$ sed -E -ibackup 's/Andreas Arnesson/Marie Grahn/' courses.txt
$ ls
courses.txt  courses.txtbackup

Här kommer courses.txt innehålla den editerade varianten och courses.txtbackup innehåller orginalet. Du kan självklart välja annat namn än “backup”.

#Avslutningsvis

Det här var lite om grunderna i regex med sed. Kör igång och testa på sidorna:

Använd sedan artikeln att luta dig mot i uppgifterna.

#Revision history

  • 2023-09-12: (A, lew) Första versionen.

Document source.

Category: regex, unix, linux, sed.