De Stream Editor - sed
De streameditor, sed,
is een niet-interactieve editor die ontworpen is om efficient,
willekeurig grote, bestanden te bewerken. Meestal wordt sed gebruikt
om een bewerking, invoer -> uitvoer, uit te voeren, m.a.w.
als filter.
Analoog aan
de shell
wordt sed
vaak aangestuurd van uit een "sed-script", waar de edit-opdrachten
in staan.
Bijvoorbeeld een file met:
1d
/aaaa/s|a|b|g
/ddd/,/fff/d
Aanroep: sed -f sed-script
Het kan echter ook door het script als (eerste) argument mee te geven.
sed '1d'
Als er meerdere edit-commando's nodig zijn, worden ze elk vooraf gegaan
door -e (van expressie):
sed -e '1d' -e '/aaa/s|a|b|g' -e '/ddd/,/fff/d'
Opties voor sed
- -n
- Normaliter worden alle invoer regels doorgeven/afgedrukt. Je zou kunnen
zeggen dat achteraan het sed-script impliciet een 'p' (print)
opdracht staat. De -n optie echter beperkt de uitvoer tot alleen
die regels waar een expliciete print opdracht voor gegeven is.
- -e expr
- Beschouw expr als een edit opdracht.
- -f file
- Haal edit opdrachten uit file file.
NB -e en -f mogen meermaals gecombineerd worden
!
sed -n -e '1d' -f xxx.sed -e 'p'
is dus een geldige aanroep, die 3 "deel" scripts combineert.
Formele beschrijving van een editopdracht
Formeel ziet elke edit opdracht er uit als:
[ adres1 , adres2 ] functie [ argumenten ]
Anders gezegd:
- Een optioneel startadres,
- Een optioneel eindadres,
- Een, verplichte, edit functie,
- Eventuele argumenten voor die edit functie.
Reguliere Expressies
In de context van sed staat het begrip adres voor regelaanduidingen.
Dat kunnen gewoon regelnummers zijn, bijvoorbeeld: 1,3d, waarbij
$ symbolisch is voor de "laatste" regel (Je kan helaas
niet rekenen). Het kunnen ook context adressen zijn, d.w.z. expressies
van de vorm /re/, waarbij re ("reguliere
expressie") een eigenschap van de regel aangeeft. Een reguliere
expressie is opgebouwt uit:
- ^
- Als ^ als eerste in de expressie staat is het synoniem
met het begin van de regel (anders "zichzelf").
- $
- Als $ als laatste in de expressie staat is het synoniem
met het einde van de regel (anders "zichzelf").
- .
- De . (punt) is synoniem voor een willekeurig karakter.
- [xyz]
- Is synoniem voor: een van de karakters uit de verzameling xyz.
Voorbeeld: [aeiou] staat voor "een klinker".
Bij veel versies van sed mag je een reeks ook verkort opschrijven
als: eerste_teken-laatste_teken, b.v. [a-z0-9].
Als de ^ onderdeel van de verzameling moet zijn moet je even uitkijken
want ...
- [^xyz]
- Is synoniem voor: een van de karakters NIET uit de verzameling
xyz (m.a.w. het "complement").
Voorbeeld: [^aeiou] staat voor "alles behalve een klinker".
Als de ^ zelf onderdeel van de verzameling moet zijn moet je 'm
niet als eerste schrijven.
- x
- Elk ander karakter x staat voor "zichzelf".
- \(re\)
- Staat voor de re tussen de haken, maar ...
- \N
- waarbij N een cijfer in de reeks 1 t/m 9 is is. Dit staat voor de tekst
die correspondeert met de Ne\(...\), eerdere,
expressie.
Voorbeeld: \([aeiou]\)\1 staat voor "een klinker" gevolgd
door "dezelfde klinker".
- re*
- Een reguliere expressie re, gevolgd door * staat voor
0 of meer keer die re. Dus:
- .* staat voor 0 of meer willekeurig karakters,
- a* staat voor 0 of meer 'a's,
- [aeiou]* staat voor 0 of meer klinkers,
- \(ab\)* staat voor 0 of meer ab, b.v. ab,
abab, ababab, enz.
Als je een van de speciale tekens nodig hebt als "zichzelf"
kan je dat aangeven door er een \ (backslash) voor te zetten.
Adressen
Het aantal adressen bepaalt wanneer de editfunctie toegepast
wordt:
aantal |
van toepassing op invoer regel(s) |
0 |
elke regel |
1 |
elke regel die correspondeert met adres |
2 |
vanaf start tot/met eerstvolgende eind (en dan weer herhaald
!) |
Voorbeelden:
- s/A/a/g
- Vervang elke 'A' door 'a' in elke regel.
- /ab/d
- Delete elke regel waar ab in staat.
- 1,3d
- Delete regel 1 t/m 3.
- $d
- Delete de laatste regel ($-4 o.i.d. werkt helaas niet).
- /aa/,/bb/d
- Delete alle regels, steeds te beginnen met de regel waar aa
instaat, tot en met de regel waar bb instaat. Herhaal dat
"recept" zolang er invoer is.
Gewone Edit Opdrachten
Hieronder staan een aantal sed-opdrachten. Er voor staat tussen
haakjes hoeveel addressen mogelijk zijn.
De meeste opdrachten die sed kent zijn analoog aan de opdrachten
die b.v. de ex editor kent.
- (1) a\
tekst
- "Append"; voeg de regel(s) toe aan de uitvoer. Als
het er meer dan één zijn moeten ze allemaal op \
(backslash) eindigen (behalve de laatste).
- (1) i\
tekst
- "Insert"; Analoog aan "append".
Het verschil tussen a en i zit in de volgorde als
de invoer regel ook afgedrukt zou worden.
- (2) c\
tekst
- "Change"; Analoog aan "append/insert". De huidige
invoerregel vervalt helemaal.
- (2) d
- "Delete"; Gooi de regel weg.
- (2) n
- "Next"; lees meteen de volgende invoer regel. De volgende
edit commando's hebben nu dus betrekking op de nieuwe invoer regel.
Wat er met de vorige gebeurt wordt bepaalt door de -n optie van
sed; zonder -n wordt ze nog afgedrukt, anders niet.
- (2) s argumenten
- "Substitute"; Er zijn in principe drie argumenten:
- Wat er vervangen moet worden (pattern)
- Waardoor het vervangen moet worden (replacement)
- Eventueel opties.
Het pattern is analoog aan de adres expressie maar nu
mag elk willekeurig teken als "delimeter" (scheiding) op treden
(dus niet alleen de /)
Het replacement argument geeft de vervangende tekst, tot aan de
volgende delimiter (totaal dus 3). Het kan twee speciale tekens
bevatten:
- & staat voor alles wat met de pattern correspondeerde.
- \N staat voor de tekst die correspondeerde met de Ne
(1 t/m 9) \(...\) sub-expressie in pattern.
De, optionele, opties kunnen zijn:
- g "global", doe het voor "alle" ... (anders
alleen de eerste).
- p "print", druk de nieuwe regel af.
- w file "write", schrijf de nieuwe regel naar
de genoemde file.
Voorbeeld: s!studen!&en! vervangt de eerste 'student' in de regel door
'studenten'.
Voor de variatie nu eens '!' als scheidings-teken gebruikt.
Voorbeeld: s/Ab/CD/g vervangt alle (g-optie) 'Ab' door 'CD'.
NB Als er meerdere s commando's zijn kunnen de p
en w opties meerdere "versies" van dezelfde invoer regel
op leveren !
Invoer/Uitvoer Opdrachten
- (2) p
- "Print"; Druk de regel(s) af.
- (2) w file
- "Write"; Schrijf de regel(s) naar file.
- (1) r file
- "Read"; Lees extra regels van file en druk ze af.
Is analoog aan de a
en i opdracht.
Buffer Opdrachten
Elke ingelezen invoer regel komt in een "huidige invoer" buffer
terecht en wordt daar bewerkt. Meestal wordt de gebufferde regel meteen
weer weggeschreven. Deze invoer buffer kan echter meerdere invoer
regels bevatten.
- (2) N
- "Next"; Lees de volgende invoer regel in en voeg die toe
aan de invoer buffer. De vorige invoer regel(s) blijven dus ook in de invoer
buffer, gescheiden door een \n (newline).
In de pattern expressie van de "substitute", kan je expliciet
naar die \n refereren, b.v. de opdracht s/\n// maakt
van de eerste 2 regels in de invoer buffer één regel.
- (2) D
- "Delete"; Gooi de eerste van de regels in de invoer buffer
weg.
- (2) P
- "Print"; Druk de eerste van de regels in de invoer buffer
af.
"Hold Space"
Naast de buffer waar 1 of meer invoer regels in staan heeft sed
nog een z.g. "hold" buffer.
- (2) h
- "hold"; copieer de inhoud van de invoer buffer naar "hold-space"
(replace).
- (2) H
- "Hold"; voeg de inhoud van de invoer buffer aan de "hold-space"
toe (append).
- (2) g
- "get"; copieer de inhoud van de "hold" buffer naar
de invoer buffer (replace).
- (2) G
- "Get"; voeg de inhoud van de "hold" buffer toe
aan de invoer buffer (append).
- (2) x
- "Exchange"; wissel de inhouden van de invoer en de hold buffer
om.
Diversen
- (2) !...
- "Do-not"; Inverteert de betekenis van de adres selectie.
voorbeeld: 1,3!d, regel 1 t/m 3 worden NIET gedelete.
voorbeeld: /aa/,/bb/!p, druk alle regels af BEHALVE de regels
in de "reeks" /aa/ t/m /bb/
- (2) {...
- "Group"; De verzameling van opdrachten, tot aan een regel
met alleen }, worden allemaal toegepast op de geselecteerde invoer
regels. Een groep mag zelf weer een groep bevatten, enz.
- (0) : label
- "Mark"; Markeer een plaats in het sed script met
het gegeven label, een naam van maximaal 8 karakters.
- (2) b label
- "Branch"; Spring naar de regel die gemerkt was met dat label.
Een blanco label staat voor "einde-script".
- (2) t label
- "Test"; Als er een substitute gelukt is, spring dan
naar label, ga anders gewoon verder met het sed-script.
- (1) =
- Drukt het regel nummer van huidige invoer regel af (de tekst
regels van de a, i, c en r opdrachten
hebben dus geen invloed).
- (1) q
- "Quit"; beëindig het sed-script.
Voorbeelden
Verwijder de 1-e en de laatste regel van de invoer
1d
$d
Als we een java of c++ file hebben kunnen we het //-commentaar verwijderen
met:
/\/\//s|//.*$||
aangenomen dat "//" niet ergens in een string stond.
Als we een pure tekst file hebben waarvan sommige regels op -
eindigen vanwege woordafbreking, kunnen we dat weer ongedaan maken met:
/-$/{
N
s/-\n//
}
Tekstueel:
Als: we een regel zien die op '-' eindigt:
dan: lees ook de volgende regel in
en: haal de '-' en de '\n' tussen de regels weg
Oefeningen
Bedenkt een sed-script, en de aanroep, die elke commentaar regel
(dus alle '# ....' regels) elimineert uit een shell-script.
Bedenk een sed-script, en de aanroep, die elke oneven regel afdrukt.
Bedenk een sed-script, en de aanroep, die elke even regel afdrukt.
Bedenk een sed-script, en de aanroep, die alle even regels achter
de oneven regels plakt.
1
2
3
4
5
6
wordt dus:
1 2
3 4
5 6
Geef een sed-script, en de aanroep, om de laatste twee velden van de
volgende invoer vooraan te krijgen. Het is een gegeven dat die twee
velden elk altijd 5 karakters groot zijn, verder is er niets van bekend.
Jan Jansen 12345 abcde
Pieter de Vries 1a3b5 fghij
Gerard van het Reve 54321 jklmn
Kees opqrs 98pw6
moet worden:
12345 abcde Jan Jansen
1a3b5 fghij Pieter de Vries
54321 jklmn Gerard van het Reve
opqrs 98pw6 Kees
Geef een sed-script, en de aanroep, die het omgekeerde van bovenstaande
doet.
Tenslotte - voor de moedige studenten
Maak een sed-script, "html.sed", die de
feitelijke tekst uit een html file kan isoleren (anders gezegd,
alle "html" "tags" elimineren).
Voor wie niet weet hoe html in elkaar zit,
bekijk de files van het vak inleiding unix
dan zie je snel genoeg hoe dat in elkaar zit.
In html files worden speciale karakters aangegeven
met een bijzondere notatie, b.v. "é"
(staat voor een é).
Om die terug te vertalen naar "gewone tekst"
zijn er sed-scripts beschikbaar iso8.sed
en iso7.sed.
Probeer eerst iso8.sed,
als dat problemen met andere programma's op levert,
gebruik dan iso7.sed.
Maak vervolgens een shell-script, "wft", dat een
"woorden frequentie tabel" maakt, d.w.z. een tabel waarin
voor elk woord staat hoe vaak het in de invoer voorkwam. Voor "woord"
geldt de gangbare definitie (letters en/of cijfers), waarbij (voor het
gemak) "1234" en "a13", etc, als woord beschouwd mogen
worden. De tabel moet gesorteerd zijn op frequentie (hoog ... laag).
Het script moet zo in elkaar zitten dat je het zowel kan aanroepen met
0 argumenten (dan leest het standaard invoer) of met een aantal filenamen
(dan leest het die files). Er komt altijd één woorden frequentie
tabel uit.
Ga er van uit dat de invoer (file(s)) gewoon tekst bevatten (dus geen
c++ code, o.i.d.). Enkelvoud/meervoud worden als aparte woorden beschouwd,
idem vervoegingen, etc. Je hoeft ook geen rekening te houden met woord-afbreking.
Denk wel aan het elimineren van leestekens, en dat in teksten woorden soms
met een hoofdletter en soms met kleine letter geschreven worden (en dan
wel als hetzelfde woord gezien moeten worden).
PS Sommige programma's willen een kode zien i.p.v. \n (newline),
die kode is \12 (staat ook in man ascii
c.q. de file /usr/pub/ascii).
Maak tenslotte een shell-script, "hwft",
die op zijn beurt de twee vorige gebruikt,
zodat de invoer nu uit 1 of meerdere html files kan komen.
Laat jouw hwft los op een paar van de .html
files in de directory
/hio/praktikum/i1/inl_unix. Bepaal
in elke tabel de eerste 5 "ongewone" woorden (dus niet woorden
zoals "de", "het", "voor", "achter",
"je", etc).
Als het goed is heb je nu per geval een aantal "trefwoorden"
gevonden die kenmerkend zijn voor die documenten.
Hint: Je zal naast sed ook gebruik kunnen maken van b.v.
"tr",
"sort"
en
"uniq".
Soms meer dan 1 keer.
Randvoorwaardes zijn:
Je mag nergens hulpfiles gebruiken (dus alleen "pipes"),
Je mag hooguit de beschikbaar gestelde sed scripts copieren,
Je mag geen awk gebruiken.
Klik hier t.z.t. voor de uitwerkingen.
Laatst veranderd op:
Mon Mar 9 15:37:37 MET 1998
Please email any comments to:
Ron Akkersdijk