\documentstyle{article}
\language \finnish
\textheight=9.5in
\voffset=-0.5in
\def\sed{{\em sed}}
\def\n{{\tt $\backslash$n}}
\parindent0pt
\parskip\baselineskip
\title{SED}
\author{Tapani Tarvainen}
\date{16.10.1989} % modified 23.2.1995
\begin{document}
%\tableofcontents
\maketitle
\section{Johdanto}
SED ({\em Stream EDitor\/}) on ei-interaktiivinen (eräajo) editori.
Se on hyödyllisin komentojonoissa, erityisesti putkitettaessa kun
ensimmäisen ohjelman tulostus on melkein sellaisenaan
sopiva toisen syötöksi, formaatti vain on hiukan väärä (kentät
väärässä järjestyksessä tms).

Sed on toiminnaltaan rivipohjainen: se lukee yhden rivin työmuistiin
({\em pattern space}),
käsittelee sen (soveltaa siihen annettuja editointikomentoja)
ja tulostaa mitä jäi jäljelle, lukee seuraavan rivin jne.
(Useamman rivin käsittely yhtaikaa, rivien siirtely jne.\
on mahdollista mutta vaatii erityistoimenpiteitä.)

Sed on erityisen kätevä paikallisluontoisten muutosten teossa.
Globaaleihin operaatioihin, kuten suurten lohkojen siirtelyyn paikasta
toiseen se ei niinkään sovellu. Yleensäkin haluttaessa
muuttaa tiedostoa "paikalla", saattaa paremmin
soveltua normaali editori (esim.\ {\em ed\/}(1)), joka lukee tiedoston
muistiin editoitavaksi ja lopuksi kirjoittaa sen takaisin.
(Useimmat editorit osaavat lukea komentoja standard inputista,
jonka voi uudelleensuunnata.  Niiden käyttö filttereinä ei sen sijaan
yleensä onnistu.)

Sed ei osaa laskea mitään, se tuntee vain kaikkein alkeellisimmat
kontrollirakenteet jne.  Jos sed-ohjelma uhkaa paisua satariviseksi
kannattaa harkita työkalun vaihtoa: varsinaisten ohjelmointikielten
ohella usein tulee kyseeseen {\em awk\/}(1) tai {\em perl} (joka ei
valitettavasti ole UNIXin standardikomento).

Sedistä (kuten UNIXistakin) on valitettavasti olemassa useita
ei-aivan-yhteensopivia versioita; seuraavassa on enimmäkseen
rajoituttu niiden suurimpaan yhteiseen osajoukkoon (poikkeuksista
on mainittu erikseen).

\section{sed-komento}

Sed-komennon syntaksi on:\newline
{\tt
sed [-n] [-e {\em script}\dots] [-f {\em sfile}\dots] [{\em file}\dots]
}

missä
\begin{itemize}

\item {\tt -n} aiheuttaa sen, ettei sed tulosta kuin ne rivit,
jotka erikseen käsketään tulostaa; muutoin se tulostaa kaikki
rivit, joiden tulostamista ei erikseen kielletä.
Saman vaikutuksen saa aikaan myös {\tt \#n} ensimmäisen komennon
alussa.  Esimerkeissä oletetaan ettei {\tt -n}:ää ole käytetty,
ellei erikseen toisin mainita.

\item {\tt -e {\em script}} ilmoittaa, että merkkijono {\em
script} sisältää editointikomennon.  (Jos {\tt -e}-optioita on
vain yksi (eikä yhtään {\tt -f}:ää), voi "{\tt -e}":n jättää
pois, ts.\ {\tt sed '{\em komento}'} on sama kuin {\tt sed -e
'{\em komento}'}.)

\item {\tt -f {\em sfile}} ilmoittaa, että tiedosto {\em sfile}
sisältää yhden tai useampia editointikomentoja.

\item Optioiden jälkeen seuraa lista tiedostonimiä.
Jos se on tyhjä, syötöksi otetaan standard input (jota vastaa
myös tiedostonimi "{\tt -}"). Jos tiedostoja on useita, ne
käsitellään niin kuin ne olisi katenoitu yhdeksi (erityisesti
myös rivinumerointi jatkuu tiedostosta toiseen).

\end{itemize}

Jos {\tt -e} ja {\tt -f} optioita on useita, ne yhdistetään
järjestyksessä yhdeksi komentojonoksi.  Komentojen kokonaismäärä
on rajoitettu, yläraja riippuu versiosta mutta sen pitäisi olla
sata tai suurempi.

Optioita {\em ei} voi yhdistää, esim.\ {\tt -nf} ei toimi
(toimii Gnu sedissä).

Tulos tulee normaalisti stdoutiin.

\section{Osoitteet}

Useimmilla komennoilla voi olla nolla, yksi tai kaksi osoitetta,
jotka määräävät mihin riveihin ko.\ komentoa sovelletaan.
Osoitteita on kahdenlaisia:

\begin{itemize}

\item {\em Numeerisia}, ts.\ rivinumeroita (1:stä alkaen);
erikoistapauksena \$ tarkoittaa viimeistä riviä.

\item {\em Sisältöosoitteita}, ts.\ viitataan riveihin jotka
sisältävät tietynlaisen merkkijonon.  Näiden syntaksi on
{\tt /{\em merkkijonolauseke}/} tai
{\tt $\backslash$x{\em merkkijonolauseke}x}, missä {\tt x} on mielivaltainen
merkki.  (Merkkijonolausekkeista myöhemmin enemmän.)

\end{itemize}

Osoitteet tulkitaan seuraavasti:

\begin{itemize}

\item Jos osoitetta ei ole lainkaan: Käskyä sovelletaan kaikkiin
riveihin.

\item Yksi osoite:  Käsky viittaa riveihin joita ko.\ osoite vastaa,
numeerinen osoite täsmälleen ko.\ riviin, sisältöosoite kaikkiin
riveihin, joilla annetunlainen merkkijono esiintyy.

\item Kaksi osoitetta:  Käsky suoritetaan alkaen ensimmäisen osoitteen
osoittamasta rivistä ja päättyen jälkimmäisen määräämään riviin
(molemmat mukaanluettuna).

\end{itemize}

Jos osoitteita on kaksi, ne voivat molemmat olla numeerisia tai
sisältöosoitteita.  Eri tapaukset tulkitaan seuraavasti:

\begin{itemize}

\item $n_1,n_2$:  Rivit $n_1$--$n_2$.
Jos $n_1>n_2$ käskyä ei suoriteta koskaan (ilman virheilmoitusta).

\item $n_1$,{\em lauseke}$_2$: Kaikki rivit $n_1$:stä alkaen ensimmäiseen
sitä seuraavaan, jolla {\em lauseke}$_2$ esiintyy, tai tiedoston loppuun ellei
sellaista löydy.

\item {\em lauseke}$_1$,$n_2$:  Alkaen ensimmäisestä rivistä, jolla
{\em lauseke}$_1$ esiintyy, riville $n_2$, tai tiedoston loppuun jos
{\em lauseke}$_1$ esiintyy ensimmäisen kerran rivin $n_2$ jälkeen.

\item {\em lauseke}$_1$,{\em lauseke}$_2$:  Alkaen riviltä, jolla
{\em lauseke}$_1$ esiintyy, sitä lähinnä seuraavaan jolla {\em lauseke}$_2$
esiintyy, ja jos sen jälkeen esiintyy taas {\em lauseke}$_1$, jälleen
siitä seuraavaan {\em lauseke}$_2$-riviin, jne.

\end{itemize}

Huom.\ Jos toinen osoite on sisältöosoite, käsky kohdistuu aina vähintään
kahteen riviin (ellei tiedosto lopu ensin).

Osoitteiden merkityksen voi kääntää niiden perään sijoitetulla
huutomerkillä (käskyä sovelletaan kaikkiin riveihin {\em paitsi} \dots).


\section{Merkkijonolausekkeet ({\em regular expressions})}

Sisältöosoitteissa ja korvaa-komennossa käytettävät merkkijonolausekkeet
tunnistavat joukon erikoismerkkejä; tarkalleen minkä joukon
riippuu versiosta, mutta ainakin seuraavien pitäisi kelvata kaikille:

\begin{description}

\item[.] Edustaa yhtä mielivaltaista merkkiä, myös rivinvaihtoa
  työmuistin sisällä (muttei sen lopussa), ja erityisesti {\tt .*}
  ei ylitä rivinvaihtoa.  (Joissakin versioissa ei vastaa rivinvaihtoa
  koskaan.)

\item[\^{}] Edustaa rivin alkua (kuviteltua nollamittaista merkkiä
  työmuistin alussa --- jos työmuistissa on useita rivejä,
  {\em ei} vastaa rivinvaihtoa sen keskellä) ollessaan lausekkeen
  alussa (muualla normaali merkki).

\item[\$] Edustaa rivin loppua (kuviteltua nollamittaista merkkiä
  työmuistin lopussa --- ei rivinvaihtoa työmuistin keskellä)
  ollessaan lausekkeen lopussa (muualla normaali merkki).

\item[$\backslash$n] Vastaa rivinvaihtomerkkiä työmuistin keskellä
  (ei sen lopussa).

\item[*] Vastaa nollaa tai useampaa kopiota edeltävästä yhden merkin
  osalausekkeesta.  (Joissakin versioissa toimii myös
  $\backslash$({\em lauseke}$\backslash$):n perässä.)

\item[[{\em merkkejä}]] Vastaa mitä tahansa hakasulkujen sisällä olevista
  merkeistä (tasan yhtä), paitsi jos ensimmäinen merkki siellä on \^{},
  jolloin vastaa mitä tahansa merkkiä jota {\em ei} ole siellä.
  Lisäksi -- kahden merkin välissä tarkoittaa väliä, esim.\ {\tt [a-z]}
  vastaa kaikkia kirjaimia a--z.  Jos joukkoon halutaan ],
  se on sijoitettava heti alku-[:n jälkeen.  Muilla erikoismerkeillä
  ei ole erikoismerkitystä hakasulkujen sisällä (paitsi
  $\backslash${\tt n} toimii).

\item[$\backslash$({\em lauseke}$\backslash$)]  Rajoittaa osan
  lausekkeesta niin että siihen voi viitata $\backslash${\em numero}:lla.

\item[$\backslash n$] missä $n$ on numero 1--9. Vastaa $n$:nnen
  sulkulausekkeen arvoa. Esim.\ 
  "{\tt $\backslash$([Kk][a-zA-Z]$\backslash$)* $\backslash$1}"
  vastaa k-kirjaimella alkavaa sanaa, joka esiintyy kahdesti
  peräkkäin yhdellä välilyönnillä erotettuna (ja molemmilla kerroilla
  joko isolla tai pienellä alkukirjaimella).

\item[$\backslash$] Jos jotakin erikoismerkkiä halutaan käyttää
  normaalina merkkinä, sen eteen on lisättävä $\backslash$
  (tai sen voi sijoittaa hakasulkuihin).

\end{description}

Näiden lisäksi ainakin seuraavat esiintyvät joissakin versioissa:

\begin{description}

\item[//]  Tyhjä lauseke vastaa lähinnä edellistä lauseketta.

\item[$\backslash<$]  Sanan alku, ts.\ kohta, jonka oikealla puolella
  on kirjain, numero tai alaviiva ja vasemmalla jotakin muuta (myös
  rivin alku).

\item[$\backslash>$]  Sanan loppu, kohta, jonka vasemmalla puolella
  on kirjain, numero tai alaviiva ja oikealla jotakin muuta (myös
  rivin loppu).

\item[$\backslash\{m$[,[$n$]]$\backslash\}$]  Toistaa edeltävää
  merkkiä (tai osalauseketta) tasan $m$, 
  ($\backslash\{m\backslash\}$), vähintään $m$
  ($\backslash\{m$,$\backslash\}$) tai $m$--$n$
  ($\backslash\{m$,$n\backslash\}$) kertaa.
  $\backslash\{0$,$\backslash\}$ on sama kuin {\tt *}.

\end{description}

(seuraavat toimivat lähinnä Gnu-sedissä)

\begin{description}

\item[$\backslash$+] tai vain {\bf +}:  Toista edellistä merkkiä
  (tai osalauseketta) yksi tai useampia kertoja.
  Sama kuin $\backslash\{1$,$\backslash\}$.

\item[$\backslash$?] tai vain {\bf ?}:  Toista edellistä merkkiä
  (tai osalauseketta) nolla tai yksi kertaa.  
  Sama kuin $\backslash\{0$,$1\backslash\}$.
  (Huom.\ se, että
  {\tt +} ja {\tt ?} saattavat toimia $\backslash$:n kanssa tai ilman
  aiheuttaa ongelmia kun niiden halutaan esiintyvän normaaleina
  merkkeinä:  Silloin ei auta muu kuin selvittää miten ne toimivat
  käsillä olevassa versiossa, tai panna ne hakasulkuihin.)

\item[$\backslash|$]  "tai"; vastaa oikealla {\em tai} vasemmalla
  puolellaan olevaa osalauseketta. Esim.\ {\tt kissa$\backslash$|koira} ja
  {\tt k$\backslash$(iss$\backslash$|oir$\backslash$)a} vastaavat
  sanoja "kissa" ja "koira".

\item[$\backslash$w]  Sama kuin {\tt [a-zA-Z0-9]}.

\item[$\backslash$W]  Sama kuin {\tt [\^{}a-zA-Z0-9]}.

\item[$\backslash$b]  Sanan raja, ts.\ kohta, jonka toisella puolella
  on kirjain tai numero ja toisella ei (kummin päin tahansa).

\item[$\backslash$B]  Sanan sisällä tai ulkopuolella, ts.\ kohta,
  jonka molemmilla puolilla joko on kirjain tai numero tai kummallakaan
  ei ole.

\end{description}

Jos lauseke täsmää tekstiin useammalla tavalla, sääntö on se,
että se vastaa niistä vasemmanpuoleisinta, ja jos niitäkin on
useita, pisintä.

\section{Editointikomennot}

\subsection{Yleistä}

Komentojen syntaksi on seuraavaa muotoa:

[osoite1[,osoite2]]käsky[argumentit]

Seuraavassa osoitteita ei ole merkitty näkyviin; käskyt
hyväksyvät 0--2 osoitetta ellei toisin ole mainittu (jotkut
käskyt hyväksyvät vain yhden osoitteen, jotkut eivät yhtään).  

Yleensä jokainen käsky on omalla rivillään; niitä voi myös
sijoittaa samalle riville puolipisteellä erotettuna
(ei välttämättä toimi kaikissa versioissa).
Jokainen erillinen {\tt -e}-optio vastaa yhtä riviä.

\subsection{Kokorivikomennot}

\def\teksti{teksti}

\begin{description}

\item[d]  ({\em delete}): Poista rivejä. 
  Suoritus jatkuu uuden rivin lukemisen jälkeen ensimmäisestä
  komennosta.

\item[n] ({\em next line}): Tulosta työmuisti
  (paitsi jos {\tt -n} optio on voimassa) ja lue seuraava rivi. 
  Suoritus jatkuu ensimmäisestä komennosta.

\item[a$\backslash$]
  ({\em append}): Tulosta \teksti\ käsiteltävän rivin jälkeen. 
  Lisättävä teksti on komentoa seuraavilla riveillä, ja jos sitä
  on useampia rivejä on kaikkien paitsi viimeisen loppuun
  lisättävä $\backslash$. Enintään yksi osoite.
 
\item[i$\backslash$] ({\em insert}): Kuten {\bf a$\backslash$},
  mutta \teksti\ lisätään {\em ennen} käsiteltävää riviä.
 
\item[c$\backslash$] ({\em change}): Kuten {\bf a$\backslash$}
  ja {\bf i$\backslash$}, mutta \teksti\ {\em korvaa} ko.\ rivit.

  Jos osoitteita on kaksi, ko.\ rivit poistetaan ja korvataan
  yhdellä kopiolla \teksti stä.

  Jos osoitteita on yksi, jokainen vastaava rivi korvataan
  \teksti llä.

  Jos osoitteita ei ole yhtään, koko tiedosto korvataan \teksti llä.
\end{description}

\paragraph{Esimerkkejä:}

\begin{itemize}

\item Poista rivit, jotka alkavat sanalla {\tt REM}, isoilla
tai pienillä kirjaimilla kirjoitettuna:
\begin{verbatim}
/^[Rr][Ee][Mm]/d
\end{verbatim}

\item Lisää tiedoston loppuun rivi \verb@*** The End ***@:
\begin{verbatim}
$a\
*** The End ***
\end{verbatim}

\item Korvaa kolme ensimmäistä riviä rivillä {\tt ALKU}:
\begin{verbatim}
1,3c\
ALKU
\end{verbatim}

\end{itemize}

\subsection{I/O-komennot}

Nämä komennot eivät vaikuta työmuistin sisältöön, ainoastaan
tulostukseen.

\begin{description}
\item[p]  ({\em print}):
  Tulosta työmuistin sisältö stdoutiin.
  Huom.\ työmuistin sisältö tulostetaan normaalisti automaattisesti
  käsittelyn lopuksi, ellei {\tt -n}-optiota ole käytetty;
  {\tt sed 'p'} tulostaisi jokaisen rivin kahdesti.

\item[l]  ({\em list}):
  Kuten {\bf p}, mutta kontrollimerkit korvataan $\backslash nnn$
  oktaali-notaatiolla ja yli 72 merkkiä pitkät rivit katkaistaan.
  Rivin sisällä olevat \n t merkitään $\backslash$illa
  rivin lopussa.

\item[w {\em $\langle$tiedosto$\rangle$}] ({\em write to file}):
  Kuten {\bf p}, mutta tulosta tiedostoon  {\em
  $\langle$tiedosto$\rangle$}. {\bf w}:n ja tiedostonimen
  välissä on oltava tasan yksi välilyönti.

\item[r {\em $\langle$tiedosto$\rangle$}] ({\em read from file}):
  Kuten {\bf a$\backslash$}, mutta lisättävä teksti luetaan tiedostosta
  {\em $\langle$tiedosto$\rangle$}. {\bf r}:n ja tiedostonimen
  välissä on oltava tasan yksi välilyönti.

  Jos komentojonossa on useita {\bf r} ja {\bf a$\backslash$} komentoja,
  niiden lisäämät tekstit tulostetaan samassa järjestyksessä kuin
  komennot esiintyvät, sen jälkeen kun kaikki muut nykyriviin
  vaikuttavat komennot on suoritettu.

\end{description}

\subsection{Korvaa-komento}

Korvaa ({\em substitute}) komennon syntaksi on seuraava:

{\tt s/{\em $\langle$merkkijonolauseke$\rangle$}/{\em korvaava teksti}/{\em 
$\langle$liput$\rangle$}}

minkä edessä voi taas olla 0--2 osoitetta.

Korvattavan merkkijonon ({\em $\langle$merkkijonolauseke$\rangle$})
rajoittimina voi käyttää kauttaviivan asemesta mitä tahansa merkkiä
paitsi välilyöntiä tai {\tt $\backslash$\tt n}:ää.

Korvaava teksti voi sisältää mitä tahansa.  Merkkijonolausekkeissa
käytetyillä erikoismerkeillä ei ole erikoismerkitystä,
ainoastaan rajoittimena käytetty merkki, $\backslash$ itse, rivinvaihto
sekä \& (ks.\ alla) on suojeltava edeltävällä $\backslash$:lla.

Korvaavassa tekstissä voi käyttää löydettyä tekstiä seuraavasti:

\begin{description}

\item[{\tt \&}] edustaa merkkijonolauseketta vastaavaa tekstiä
  kokonaisuudessaan.

\item[{$\backslash n$}], missä $n$ on jokin numero 0--9,
  edustaa  $n$:nnen sulkulausekkeen sisältöä merkkijonolausekkessa.

\end{description}

\paragraph{Liput:} {\bf s}-komento tuntee seuraavat liput:

\begin{description}

\item[g]: Korvaa kaikki esiintymät (oletuksena vain ensimmäinen
  joka riviltä korvataan).

\item[$n$]: Korvaa vain $n$:s esiintymä joka rivillä, kun
  $n$ on kokonaisluku 1--512.

\item[p]: Tulosta rivi stdoutiin jos $\langle$merkkijonolauseke$\rangle$
  löytyi (ja korvattiin).

\item[w {\em $\langle$tiedosto$\rangle$}]:  Kuten {\bf p}, mutta
  tulosta nimettyyn tiedostoon stdout:in asemesta.

\end{description}

Nämä voivat esiintyä millaisina yhdistelminä tahansa, paitsi
{\bf p} ja {\bf w} eivät kaikissa versioissa voi esiintyä
yhtaikaa (ei myöskään useita {\bf w}-optioita).

\paragraph{Esimerkkejä}

\begin{itemize}

\item Muuta jokainen "tex", "TEX" jne.\ muotoon "TeX":
\begin{verbatim}
s/[Tt][Ee][Xx]/TeX/g
\end{verbatim}

\item Vaihda jokaisen rivin kahden ensimmäisen sanan järjestys,
olettaen että sanat muodostuvat kirjaimista a--z ja niiden välissä
on mahdollisesti pilkku, piste tai puolipiste (enintään yksi
näistä) sekä välilyöntejä:
\begin{verbatim}
s/^\([a-zA-Z][a-zA-Z]*\)\([,.; ] *\)\([a-zA-Z][a-zA-Z]*\)/\3\2\1/
\end{verbatim}

\item Lisää jokaisen "defined"-sanan sisältävän rivin alkuun
kolme huutomerkkiä:
\begin{verbatim}
s/^.*defined/!!!&/
\end{verbatim}
{\em tai}
\begin{verbatim}
/defined/s/^/!!!/
\end{verbatim}

\end{itemize}

\subsection{Muunna-komento}

Muunna ({\em transform}) komento muuttaa yksittäisiä merkkejä
toisiksi. Sen syntaksi on seuraavanlainen:

{\tt y/{\em merkkijono1}/{\em merkkijono2}/}

Jokainen {\em merkkijono1}:ssä esiintyvä merkki korvataan
{\em merkkijono2}:ssa vastaavalla paikalla olevalla merkillä.
{\em merkkijono1}:n ja {\em merkkijono2}:n on oltava yhtä pitkiä.
Muunnosta sovelletaan kuhunkin merkkiin vain kerran.

Esim.

{\tt y/ab/ba/}

vaihtaa kaikki a-kirjaimet b:ksi ja päinvastoin;

{\tt y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/}

muuttaa kaikki pienet kirjaimet isoiksi.


\subsection{Monen rivin käsittely yhtaikaa}

\begin{description}

\item[N] Lue seuraava rivi työmuistiin sen nykyisen sisällön perään.
  Väliin jää yksi rivinvaihto (\n).

\item[D] Tuhoa työmuistin ensimmäinen rivi (alkuosa ensimmäiseen
  \n:ään saakka. Suoritus jatkuu ensimmäisestä komennosta.
  Jos työmuisti tyhjenee (siellä on on vain yksi \n\ lopussa),
  sinne luetaan seuraava rivi (toimii tällöin täsmälleen kuten
  {\bf d}). Ei hyväksy yhtään osoitetta.

\item[P] Tulosta työmuistin ensimmäinen rivi (alusta ensimmäiseen
  \n:ään saakka).  Ei hyväksy yhtään osoitetta.

\end{description}

Näitä käytetään yleensä ryhmittely- ja hyppykomentojen kanssa.

Yksinkertaisia monen rivin kuvioita voi toki etsiä muutenkin:
Esim.\ seuraava etsii paikat, joissa sama sana esiintyy
rivin lopussa ja seuraavan alussa, ja poistaa jälkimmäisen
esiintymän.

\begin{verbatim}
N
s/\([a-zA-Z][A-Za-z]*\) *\n *\1/\1\n/
P
D
\end{verbatim}

\subsection{Apumuistin käyttö}

Editointioperaatioihin käytettävän työmuistin lisäksi on käytettävissä
erillinen apumuisti ({\em hold area}).  Suorituksen alkaessa se on
aina tyhjä.

\begin{description}

\item[h] Kopioi työmuisti apumuistiin.  Apumuistin aiempi sisältö
  tuhoutuu.

\item[H] Kopioi työmuisti apumuistiin sen nykyisen sisällön perään.

\item[g] Kopioi apumuisti työmuistiin.  Työmuistin aiempi sisältö
  tuhoutuu.

\item[G] Kopioi apumuisti työmuistiin sen nykyisen sisällön perään.

\item[x] Vaihda työmuistin ja apumuistin sisällöt keskenään.

\end{description}

Esim. Siirrä tiedoston ensimmäinen rivi viimeiseksi:

\begin{verbatim}
1h
1d
$G
\end{verbatim}

Käännä rivit päinvastaiseen järjestykseen (tulosta viimeinen
ensimmäiseksi jne):

\begin{verbatim}
#n
G
h
$p
\end{verbatim}

Huom.\ Apumuistin koko on rajoitettu (raja saattaa jopa olla melko
pieni); tämäkin esimerkki todennäköisesti kaatuu, jos tiedosto on
suuri.


\subsection{Suorituksen ohjauskomennot}

\begin{description}

\item[!] "Älä": Käännä osoitteen merkitys, ts.\ seuraavaa komentoa
  sovelletaan kaikkiin riveihin {\em paitsi} edeltävää osoitetta
  (osoiteparia) vastaaviin.

\item[$\{$\ $\}$] Ryhmittely:  Samaa osoitetta sovelletaan joukkoon
  komentoja.  Käytetään seuraavasti:

  $\langle${\em osoite1\/}$\rangle$[,
    $\langle${\em osoite2\/}$\rangle$]$\{$[{\em komento1\/}]\newline
  {\em komento2}\newline
  \dots\newline
  $\}$\newline

  Ryhmiä voi olla sisäkkäin (enintään 100 tasoa).

\item[:$\langle${\em nimiö\/}$\rangle$]  Merkitsee kohdan johon
  {\bf b}- tai {\bf t}-komennolla voi hypätä.  Enintään 7 merkkiä.
  Ei osoitetta.

\item[b$\langle${\em nimiö\/}$\rangle$]  Ehdoton hyppy.  Jos
  $\langle${\em nimiö\/}$\rangle$ puuttuu, hyppää komentojonon loppuun.

\item[t$\langle${\em nimiö\/}$\rangle$] Ehdollinen hyppy.  Hyppää
  jos yksikin korvaa-komento on onnistuneesti korvannut jotakin
  rivin lukemisen tai edellisen {\bf t}-komennon jälkeen;
  ellei, suoritus jatkuu seuraavasta komennosta.

\end{description}

Ryhmittelyä voi käyttää mm.\ erilaisten osoiteyhdistelmien
tekoon:

\begin{verbatim}
1,10{/^REM/d
}
\end{verbatim}
poistaa REM-alkuiset rivit 10:n ensimmäisen joukosta;

\begin{verbatim}
#n
1,30{11,20!p
}
\end{verbatim}
tulostaa rivit 1--10 ja 21--30.

Sisältöosoitteet testaavat työmuistin senhetkistä sisältöä;
{\bf b}-komentokin voi siten itse asiassa olla ehdollinen hyppy.

\subsection{Sekalaisia komentoja}

\begin{description}

\item[=] Tulosta käsiteltävänä olevan rivin numero (rivin alkuun
  jos tämä itse tulostetaan).  Hyväksyy enintään yhden osoitteen.

\item[q] ({\em quit}):  Lopeta editointi välittömästi.
  Työmuistin sisältö käsitellään kuin olisi hypätty komentojonon
  loppuun ja lopetetaan siihen (uutta riviä ei enää lueta).
  Vaatii tasan yhden osoitteen.

\item[\#] Kommentti: {\tt \#}:lla alkavat rivit (samoin tyhjät rivit)
  eivät vaikuta mitään.  Poikkeuksena {\tt \#n} ensimmäisen rivin
  alussa, joka saa aikaan saman vaikutuksen kuin {\tt -n}-optio.

\end{description}

\section{Rajoituksia}

Eri sed-versiot asettavat erilaisia rajoituksia ohjelmien koolle yms.
Seuraavat rajat edustavat jonkinlaista minimiä (näihin mahtuvan
pitäisi mennä läpi kaikista).

\begin{itemize}

\item Komentojen määrä:  Enintään 100.

\item Nimiöiden määrä: Enintään 48.

\item Nimiöiden pituus: Enintään 7 merkkiä.

\item Ryhmittely:  Enintään 100 sisäkkäistä ryhmää.

\item Komentorivin pituus:  Enintään 4000 merkkiä.

\item Työmuisti: Enintään 4000 merkkiä.

\item Apumuisti:  Enintään 4000 merkkiä.

\item Tiedostot:  {\bf w}-komennoilla voi kirjoittaa enintään
  10:een eri tiedostoon, tai 9:ään jos {\bf r}-komentoa on käytetty.

\item Alkutyhjät: Jotkut versiot poistavat välilyönnit ja tabit
  rivin alusta.

\item Merkkijonolausekkeet:  Ainoat erikoismerkit, joiden voi luottaa
  toimivan samalla tavalla, ovat {\tt . * [] \^{} \$ $\backslash$(
  $\backslash$) $\backslash${\em numero}} ja $\backslash${\tt n}.

\end{itemize}

Käytettävä shell asettaa lisäksi omat rajoituksensa (komentorivin
pituus on rajallinen, rivinvaihdon syöttäminen ei onnistu tms),
jotka voi yleensä kiertää käyttämällä {\tt -f}-optiota.

\newpage

\section{Esimerkki: C-prototyyppien muodostus}

\begin{verbatim}
# PROTO.SED - build ANSI-style C function prototypes from K&R-style source
# Usage: sed -f proto.sed [file(s)]
#
# Assumes function definitions begin at column 1.
# Comment delimiters inside strings aren't handled properly,
# nor can this cope with variable argument lists,
# and of course #if's and macros can cause no end of trouble.
#
# Tapani Tarvainen 10/16/89
#
# junk initial comments
/\/\*/{
:COM
# try deleting /* ... */
s-/\*.*\*/--
tNOCOMM
# didn't work, get another line
N
# junk up to newline (comments can be loooong ...)
s-/\*.*\n-/\*-
# t below jumps always, but b wouldn't clear substitution flag
tCOM
:NOCOMM
}
# look for lines beginning with a letter ('_' counts as a letter)
/^[a-zA-Z_]/{
# look for left parenthesis; anything but letter, digit, * or
# whitespace before it means this can't be function definition
:PAREN
/^[^(]*[^a-zA-Z0-9_* 	\n(]/bQUIT
/(/bBRACE
N
# check for comments within
\-/\*-bCOM2
bPAREN
:COM2
s-/\*.*\*/--
tPAREN
N
s-/\*.*\n-/\*-
tCOM2
# then read up to { 
:BRACE
# ); means this is a declaration or ready prototype, don't touch it
/)[ 	\n]*;/bQUIT
s/{/;/
tGOTALL
N
# check for comments again
\-/\*-bCOM3
bBRACE
:COM3
\-/\*.*\*/-tBRACE
N
s-/\*.*\n-/\*-
tCOM3
:GOTALL
# we've got it all (and no comments left)
# convert newlines and tabs to spaces
s/[\n	]/ /g
# convert "int m, n;" into "int m; int n;" etc.
:DUPTYPE
s/\([);] *\)\([a-zA-Z_][a-zA-Z0-9_ ]* \)\([^,;]*\),/\1\2\3; \2/
tDUPTYPE
# match names before and after ) and move type specifiers inside parens
:MATCH
s/\((.*\)\([a-zA-Z_][a-zA-Z0-9_]*\)\(.*\))\([a-zA-Z0-9_*# ]*[* ]\2\);/\1\4\3)/
tMATCH
# prepend "int " to those still typeless
s/\([(,] *\)\([a-zA-Z_][a-zA-Z0-9_]*\)\( *[),]\)/\1int \2\3/g
# if param list is empty, insert "void"
s/(\( *\))/(\1void)/
# if function type is missing, insert "int"
s/^[a-zA-Z_][a-zA-Z0-9_]* *(/int &/
s/^static \([a-zA-Z_][a-zA-Z0-9_]* *(\)/static int \1/
# final polish: discard extra spaces &c
# (this is the place to change if you want more spaces &c in output)
s/  */ /g
s/( /(/
s/ ;/;/
# uncomment the next two lines to get each parameter to a line of its own
#s/\(,\) */\1\
#	/g
p
:QUIT
}
d
#
\end{verbatim}

\end{document}
