# FAQ Tips > Hier Suchen und Finden, Links, Tutorials >  RegEx Tutorial Teil2 mit Einführung in sed

## BetterWorld

_Dieser Teil baut auf Teil1 hier im Forum auf._

*Einführung*
In ersten Teil waren die RegExes ziemlich genau gleich. Und letztlich sind sie auch gleich. Nur die Handhabung in den jeweiligen Programmen ist etwas unterschiedlich und verwirrt deshalb den Einsteiger. 

Ein großer Teil der Verwirrung stammt daher, dass man im Netz meist nur Einzeiler findet. Manche wissen gar nicht, dass man auch mit *sed* und *awk* richtige Scripte schreiben kann. Man braucht nur eine Datei mit einer entsprechenden Shebangzeile erstellen. 


*Shebang Intermezzo*
Wenn die allererste Zeile einer Datei eine Shebangzeile enthält UND diese Datei ausführbar ist, so übergibt die *sh*ell (welche auch immer) dem Kernel diese Datei und bittet um Ausführung, wenn man diese Datei direkt aufruft. Der Kernel wertet dann die allererste Zeile aus und findet den Shebang. In dieser Zeile ist der "Interpreter" angegeben, der diese Datei ausführen soll.
Ein *#!/bin sh* weist den Kernel an, die Standard- *Sh*ell auf diesem System mit sich selbst als auszuführendes Script samt eventuellen Parametern zur Ausführung zu übergeben. 
Da ein Shebang mit *#* beginnt, wird diese Zeile dann vom eigentlichen Interpreter, für den das nur eine Kommentarzeile ist, überlesen.

Ein Beispiel zum Ausprobieren:


```
# wir erzeugen ein "ECHO" Skript: (der folgende Befehl umfasst 4 Zeilen)
cat > echobang << EOF
#!/usr/bin/echo Was für ein Blödsinn!
egal, was hier steht, es wird nicht einmal gelesen.
EOF

# machen das Skript "echobang" ausführbar
chmod +x echobang

# und rufen es auf 
# Vorsicht! Hier ist der Systemprompt zur Verdeutlichung mit angegeben.
looser@computer:~/testdir> ./echobang
Was für ein Blödsinn! ./echobang
```

Der Kernel hat also tatsächlich den "Interpreter" *echo* mit dem "Optionen" *Was für ein Blödsinn!* und dem Pfadnamen der auszuführenden Datei *./echobang* aufgerufen.
Da der *echo* Befehl nichts anderes tut als seine Parameter auszugeben, tut er das und schreibt in die Konsole *Was für ein Blödsinn! ./echobang*. Und das Programm ist zu Ende. Ohne Fehler.
Zum Namen *Shebang* sei noch angemerkt, dass es eigentlich -und genderkorrekt- *Sharpbang* heißt. Das *#* spricht sich Englisch "sharp" und *!* ist mit Nachdruck, also laut und somit BANG! Aber Shebang hat sich als Verballhornung eingebürgert, als die Linuxer noch nicht genderkorrekt waren. *Räusper*

Da nun *sed* und *awk* die Option Script*-f*ile kennen, können wir einfach in eine Datei namens *UnserGenialScript* als allererste Zeile eine entsprechende Shebangzeile schreiben, diese Datei dann ausführbar machen und sie einfach mit z.B. *./UnserGenialScript ZuBearbeitendeDatei* aufrufen. Zumindest eine *ZuBearbeitendeDatei* erwarten ja *sed*, *awk* und *grep*, falls nicht durch eine Umleitung oder eine Pipe von der *St*an*d*arde*in*gabe gelesen werden soll.


```
#Ein paar Shebangs
#!/usr/bin/sed -f
#!/usr/bin/sed -rnf
#!/usr/bin/awk -f
#!/usr/bin/echo
#!/usr/bin/irgendeinSkriptOderProgramm -IrgendwelcheOptionen
```

Ob solche Shebangs Sinn machen, hängt lediglich vom "Interpreter" ab. Zulässig ist jedes Programm.
_Anmerkung:Man kann auch env nach dem Interpreter suchen lassen. 
Ein Shebang, wie #!/usr/bin/env bash, liese env zuerst nach der bash suchen (die nicht unbedingt in /bin/bash steht, wie z.B. auf Applekisten); der Rest läuft dann, wie gehabt. Nur funktioniert das mit sed nicht sonderlich gut. Also den tatsächlichen Pfad von sed, den ein which sed ausspuckt, verwenden.
Auch lassen sich die Optionen einzeln schreiben -r -n -f. Aber auch das funktioniert nicht. Also bei mehreren Optionen alles zusammenfassen zu -rnf_


_SED der StreamEDitor_
*sed* liest einen Stream. Der Stream kann von der *St*an*d*arde*in*gabe stammen oder einer Datei. Gibt man mehrere Dateien hintereinander an, so behandelt *sed* alles als einen einzigen Stream. (und kennt natürlich Schalter um genau das wieder zu unterbinden. Diese eher selten verwendete Option, die man sich nicht zu merken braucht, ist *-s* oder in Langform *--separate*)

Auf jede gelesene Zeile werden alle im *sed* Script angegebenen Befehle angewendet. Je nachdem, ob der Schalter *-n* beim Aufruf angegeben worden ist, wird die Zeile dann ausgegeben. *-n* ist gleichbedeutend zu *--quiet* oder zu *--silent*. Alle drei unterdrücken die Ausgabe, die in den meisten Dokus "auto-print" genannt wird. 

Man "druckt" dann innerhalb des Scriptes mit dem *sed*-Befehl *p*rint._Merke:
Alle sed Befehle bestehen nur aus einem Buchstaben. 
Ein paar Wenige aus einem Buchstaben mit nachfolgendem \ (z.B. a\)
(Nur der Befehl substitute weicht davon ab.)_
Damit sind folgende Befehle völlig gleichwertig:

```
echo "Hallo sed!" | sed -n 'p'
echo "Hallo sed!" | sed  ' '           #ein Leerzeichen
echo "Hallo sed!" | sed  ''            #kein Leerzeichen
echo "Hallo sed!" | sed -n -e 'p'
echo "Hallo sed!" | sed  ' 


      ' # erst hier endet das "Leerscript"
```

Im ersten Script schalten wir das "automatische Drucken" aus, haben dafür für jede Zeile (hier nur eine) den Befehl *p*, der dann *Hallo sed!* ausgibt.
Das zweite beinhaltet nur ein Leerzeichen zwischen den *' '*, tut also nix und will nicht mal spielen. Aber da der Schalter *-n* fehlt, gibt halt *sed* die Zeile trotzdem wieder aus.
Das dritte Script hat nur die Apostrophe, also ein echtes Leerscript. Tut aber dennoch das Gleiche.
Immerhin können diese genialen Scripte als *cat*- Ersatz dienen.
Sie sind damit die absolut kürzesten gültigen *sed* Scripte.

Das vierte Script verwendet *-e*xpression. Auch *grep* kennt diesen Schalter. 
Er kann beliebig oft angegeben werden. Man kann ein ganzes *sed*-Script auf eine Kette von *-e* Ausdrücken verteilen. Ein *echo "Hallo sed" | sed -n -e p -e p* gibt die Zeile also zweimal aus. Diese *-e*xpressions werden von links nach rechts abgearbeitet.  Sogar das für die *bash* wichtige Quoting kann man hier weglassen.
Nur kaum jemand verwendet diese Schreibweise, die ja auch wenig Sinn macht und mehr Schreibarbeit bedeutet. Sie hat wohl eher historische Gründe, weil man ja verschiedene Programme immer "gleich" haben wollte.

Das vierte und mehrzeilige Script, bestehend aus Leerzeichen und NewLines soll nur zeigen, dass man JEDES *sed* Script auch mehrzeilig schreiben kann, was die Lesbarkeit ganz enorm erhöht. Und damit auch spätere Wartung enorm vereinfacht.
Ein nicht zu unterschätzender Vorteil ist auch, dass man Kommentare verwenden kann. Wenn das Kommentarzeichen *#* nicht in einem RegEx ( also zwischen zwei *//*) steht, leitet es einen Kommentar ein, der dann bis zum Zeilenende reicht. Viele Kommentare machen ein Script auch nach Monaten noch lesbar. Sogar in einem Einzeiler *sed* Script kann man einen Kommentar verwenden, was natürlich den Rest des Scriptes naturgemäß abschaltet. Das ist höchstens zum rudimentären Debuggen eines langen Einzeilers nützlich, also Unsinn, aber syntaktisch korrekt.

Wie in der *bash* dient das *;* als Befehlstrenner.
Schreibe ich ein *sed* Script in einer Zeile, so muss ich die einzelnen Befehle mit einem *;* trennen.
Und ebenso, wie in einem *bash* Script,  kann ich die einzelnen Befehle durch ein NewLine trennen._TIPP:
Wenn ihr irgendwo einen nicht mehr lesbaren sed Einzeiler seht, kopiert ihn in eine Datei und fügt nach jedem ; ein NewLine ein. Damit kann man solche Magie leicht entzaubern.
Das gilt natürlich nur für Semikola, die NICHT innerhalb eines RegEx_ _stehen__,_ _also innerhalb zweier syntaktisch zusammengehörenden //_  
Damit wir nun ein wenig Üben und Demonstrieren können, nehmen wir eine Datei mit Testdaten.
Am besten erstellen wir uns ein Übungsverzeichnis im Home und wechseln dorthin.
Die folgende Codebox enthält einen einzigen *cat* Befehl über viele Zeilen. Einfach komplett in dem Testverzeichnis ausführen und wir haben eine Datei names *testdata* erzeugt.


```
cat > testdata << EOD
Dies ist die erste Zeile.
        diese komische Zeile hat einen Tabulator am Anfang.
 und die eine Leerzeichen.
- oder mal mit einem Binde - Strich anfangen?
#9 Dieser Latten#zaun ist ausnahmsweise kein Kommentar, sondern meint "Zeile Nummer 9"!
# Ich weigere mich, diesen Blödsinn zu kommentieren.
computer.example.com 192.168.0.10
rechner.example.com 192.168.0.22
192.169,0.82  box.example.com
Vorsicht! Vorher stand eine ganz leere Zeile!
Diese Testdatei kostet 34,5$ oder 29,34
Und jetzt fix her mir dre Kohle!
Dieser Unsinn stand in der Datei /home/looser/tutorials/sed/testdata
Sie wurde aber mit "mv /home/looser/tutorials/sed/testdata /home/user/reiner\ Blödsinn/echt/" verschoben 
EOD
```

Ab hier werde ich in Codeboxen nicht mehr unbedingt  *sed -rn ' *   und das schließende * ' testdata* schreiben.
Sind also in einer Codebox nur noch *sed* Befehle zu lesen, so beziehen sie sich immer auf unsere *testdata* Datei.
Wie ihr die Befehle ausführt, ist egal.
Egal ob als Einzeiler, Mehrzeiler oder richtige Scriptdatei.


*Das -n Flag*
 Das *-n* ist wohl die am häufigsten verwendete Flag. Das Ausschalten von auto-print brauchen wir fast immer. Deshalb kann man es auch innerhalb eines Scriptes angeben.


```
sed '#n
p' testdata
```

Es muss dazu ganz am Anfang der ersten Zeile stehen und funkioniert somit natürlich nicht in einem Einzeiler. Man kann dahinter noch schreiben, was man mag, wie in einem Kommentar. 
Ich nutze das hier, um die Flags anzugeben mit denen *sed* aufzurufen ist. Also ein *#nr* meint ab sofort, dass der Aufruf *sed -rn* lautet.
Das *-n* Flag ist kein Schalter. Schreiben wir *sed -n '#n ...\n......'* so bleibt das auto-print ausgeschaltet.
Genau, aufmerksamer Leser, beim Aufruf ist die Reihenfolge der Flags egal, innerhalb eines *sed* Scripts nicht.
*-f* ist die Ausnahme, da diesem Flag immer ein Pfadname zu folgen hat. Stünde es z.B. so dazwischen *-rfn*, so erhielten wir eine Fehlermeldung, dass die Datei *n* nicht gefunden werden könne. Das ist auch der Grund, weshalb es im Shebang am Ende zu stehen hat.
Diese Verhalten kennen wir von vielen Befehlen. *tar, rpm* um nur ein paar zu nennen.


*Zeilen Adressen und Bereiche*
*sed* selbst kennt nur wenige Befehle. Aber allen Befehlen kann eine Adresse vorangestellt werden, was bewirkt, dass der Befehl nur für diese Adresse ausgeführt wird. Adressen können schlichte Zeilennummern sein oder */RegEx/* Ausdrücke, die letztlich über eine Suche eine Adresse bezeichnen.


```
#n - Flag schaltet auto-print aus
5p                 # druckt Zeile Nummer 5; Zeile 1 ist also tatsächlich Zeile 1
11p                # druckt Zeile 11
//p               # druckt auch Zeile 11
#                    einen Bereich drucken
1,3p               # druckt Zeile 1 bis drei
/Latte/,/192/p     # druckt von Zeile, die "Latte" enthält, bis zur Zeile, die "192" enthält
```

Der RegEx *//* passt nur in Zeile 11, da nur in Zeile 11 ein  Zeichen vorkommt.
Bereiche folgen dem schlichten Muster *[Beginn][Komma][Ende]*, wobei es egal ist, ob für Start und Ende eine absolute Zeilennummer oder ein RegEx verwendet wird.
Die RegExadressierung */192/* zeigt außerdem, dass -wie zu erwarten- das erste Vorkommen eines Treffers einen Bereich beginnt oder abschließt.
Von den drei Zeilen mit 192 ist die, die "computer" enthält, die erste.


*RegExes Alpha und Omega*
In einem RegEx meint das *^* den Anfang und *$* das Ende. 
Bei *sed* bezeichnet das *$*olllar Zeichen außerhalb von *//* die letzte Zeile, also das Ende der Eingabe. Innerhalb von *//* bezeichnet es das Ende einer Zeile. Wir wissen ja: *sed liest seine Eingabe Zeile für Zeile. Auf jede Zeile werden alle Befehle eines Scriptes angewendet.* Und RegExes werden halt nun mal nur auf Zeilen angewendet. Außerhalb eines RegEx kann der *$*ollar also getrost die "Adresse" der letzten Zeile sein.
Somit ist auch klar, dass der RegEx */^$/* nur auf eine leere Zeile passt.
Suche / an Anfang der Zeile *^* ein folgendes Ende *$* der Zeile und der RegEx endet */*. Eine Zeile, in der dem Anfang gleich das Ende folgt, ist nun mal nur eine leere Zeile.


*Der = Befehl*
Ja, das *=* ist tatsächlich wieder ein echter *sed* 1-Zeichen Befehl. Er tut nichts anderes, als die Zeilenummer auszugeben.
Eine sehr geekige Variante des *wc -l* wäre also


```
sed -n '$='
```

Das *$* adressiert die letzte Zeile, und der Befehl *=* gibt Zeilennummer aus.


*sed Syntax*
Generell folgt *sed* dem schlichten Syntaxschema
*[Adresse[,Adresse]] Befehl [Optionen] [;|\n]* 
Ein *sed -n '=$'* geht also nicht, wir würden ja die Adresse *$* nach dem Befehl *=* schreiben, was syntaktisch falsch ist.

Mit dem jetzigen Wissen können wir uns schon eine ganz nützliche Shellfunktion schreiben, die uns die Schalter eines Befehls anzeigt. (Natürlich könnt ihr es auch als Shellscript schreiben)
Der Aufruf erwartet zwei Parameter *getflag Befehl Option*


```
# getflag  als Shell function
getflag(){
    man $1 | sed -n -r '/^[[:blank:]]+'$2'/,/^$/p'
}
```

Wir rufen *man* mit einem Befehl auf, das via *$1* den gewünschten Befehl erhält. Die Ausgabe davon *|* pipen wir zu *sed*, das ohne *-n* auto-print nichts druckt, außer wir verwenden *p*rint. Mit *-r* schalten wir noch die ExtendedRegExes ein. Die Suche */* beginnt. Der RegEx sucht am Anfang *^* nach mindestens einem einmal vorkommenden Leerzeichen *[[:blank:]]+*. Wir wissen, dass eine Zeichenklasse *[]* genau ein Zeichen repräsentiert. Durch den Quantifikator  *+* (Mengenangabe) verlangen wir eines oder mehrere dieser Zeichen. Innerhalb dieses EINEN Zeichens, das jetzt mehrfach vorkommen darf, definieren wir als Suche *[:blank:]* ein Whitespacezeichen (siehe Teil 1). Jetzt kommt mit *'$2'* von der Shell das zu suchende Flag und die Suche */* endet. Das Komma trennt den vorherigen StartadressRegEx vom EndBereichsRegEx. Der Bereich geht also von der Zeile, in der das z.B. *-a* Flag nach einigen Leerzeichen beginnt, bis zur nächsten leeren Zeilen, was dann ge*p*rintet wird._Anmerkung:
Der Begriff Whitespace stammt aus der Steinzeit, als man noch alles auf sehr lauten Nadeldruckern mit Endlospapier druckte. Zeichen, die ausgedruckt nur den Nadelschreibkopf weiterbewegten, also quasi weiße Zeichen (Papier ist normalerweise weiß) druckten.
Dazu gehört -ganz klar- das Leerzeichen, aber auch Tabulatoren und all die graphischen Zeichen, die ähnliches bewirken._ 
Der Aufruf von *getflag ls -a* spuckt also die Erklärung vom Schalter *-a* des Befehls *ls* aus, wie es in *man ls* geschrieben steht.
Liest man irgendwelche Dinge in denen Linuxbefehle mit irgendwelchen Optionen verwendet werden, die man nicht kennt, so spuckt diese Funktion die benötigte Erklärung ganz schnell aus. Schon recht nützlich. 

Rufen wir sie mit *getflag date %* auf, so erledigt sie das gleiche, was wir in Teil 1 dieses Tutorials mit *alias datef="man date | grep -E '^[[:blank:]]+%'"* erledigt haben.
Zum Vergleich:

```
man date | grep -E '^[[:blank:]]+%'
 man $1 | sed -n  '/^[[:blank:]]+'$2'/,/^$/p'
```

  Schön zu sehen ist hier, dass sich der RegEx kaum unterscheided. Bei *grep* suchen wir nach dem buchstäblichen Prozentzeichen, beim *sed* suchen wir nach Zeichen, die wir von der *bash* vor der Ausführung des *sed* Befehls durch den Inhalt von *$2* ersetzen lassen. Die Suche ist genau gleich: Zeilen, die mit beliebigen Leerzeichen (oder Whitespacezeichen) beginnen, gefolgt von einem z.B. -a oder einem %. 
Die "Startadresse" im *sed* Befehl ist exakt gleich zu unserem *grep* Ausdruck.

*Übergabe von Parametern an sed*
Der obige *sed* Befehl beginnt mit *man $1*. Die *bash* ersetzt das *$1* mit dem ersten Argument, mit dem wir die function aufgerufen haben, nämlich dem *ls*. Dann kommt das *sed* Script *'/^[[:blank:]]+'*. Wenn etwas zwischen zwei *'* Apostrophen steht, nimmt die *bash* KEINERLEI Ersetzungen vor. Aber das Script endet hier nach *+'* und dem folgt -wir sind nun ganz normal im Shellscript/function und die *bash* ersetzt ganz normal das *$2* was bei unserem Aufruf *getflag date %* schlicht das Prozentzeichen ist. Und nun kommt der Rest des Scriptes.
*sed* "sieht" also nur:   */^[[:blank:]]+%/,/^$/p* 
Dieser Technik, ein Script zu escapen, werden wir noch öfter begegnen, und viele von euch werden sie wohl auch schon einsetzen.
Eine übliche Methode irgendwelche Shellvariablen irgendwo einzupflanzen.



*der s Befehl (substitute)*
Der wohl am häufigsten verwendete und am weitesten bekannte Befehl von *sed*. Und wohl der mächtigste.
Er wird sogar in der Doku *info sed* als das Schweizer Taschenmesser bezeichnet. 
Er folgt der Syntax *s / RegexSuche / Ersetzung / Optionen*
Dieser Befehl kennt sehr viele Optionen. In diesem Teil werde ich nur die Basics von *s* erklären; der nächste Teil dieses Tutorials wird sich damit eingehender befassen. 


*RegExes Gruppierung und späterer Zugriff*
Bislang haben wir relativ einfache Dinge mit den RegExes angestellt. Wir haben nur gesucht und gedruckt. Aber es heißt ja *S*tream*ED*itor.
Wir können also während ein Stream durchrauscht Teile davon editieren. Und die Teile sind schlicht Zeilen.
Nochmal: *sed liest seine Eingabe Zeile für Zeile und auf JEDE Zeile werden ALLE Befehle eines Scriptes angewendet.* (Ob sie zutreffen, oder nicht, also ausgeführt werden, ist eine andere Geschichte.
Um nun den *s//* Befehl sinnvoll einsetzen zu können, brauchen wir noch die Gruppierung von Treffern in RegExes.
Das tun runde Klammerpaare. Die wir aber vorerst noch nicht mit *-r* auf *ExtendedRegExes* umschalten, müssen wir sie mit dem Backslash escapen. (Das gucken wir uns im nächsten Teil dieses Tutorials genauer an).
Was wir also innerhalb von *\(    \)* schreiben wird zu einer Gruppe zusammengefasst, auf die wir später wieder zugreifen können.
Hiermit *\( blablubber \)  \( hicks \)*  definieren wir zwei Gruppen. Gruppe *1* enthält *[einLeerzeichen]blablubber[einLeerzeichen]* und Gruppe *2* *[einLeerzeichen]hicks[einLeerzeichen]*
Wollen wir später darauf zugreifen, so genügt ein *\1 \2,* was dann *hicks   blablubber* ergeben würde.
Zwischen *hicks* und *blablubber* stehen nun *3* Leerzeichen. Je eines von den Gruppen und eines, das aus dem Zwischenraum von *\1* und *\2* stammt.
Man sieht, dass die Reihenfolge, in der wir auf solche Gruppen zugreifen, beliebig ist. Und auch leicht einsehbar, dass uns 9 solcher Gruppen zur Verfügung stehen. In anderen Programmen mag das anders sein. Bei *sed* sind wir auf einstellige Gruppenzahlen beschränkt.

Natürlich wollen wir nicht endlos viele Backslashes tippen. Dafür gibt es:
*Das -r Flag*
Damit müssen wir nicht mehr *\( \)* schreiben, wenn wir gruppieren wollen. Und es wirkt auch als Umschalter für folgende Sonderzeichen *+ ? { * und *}* Auch hier gibt es noch einen Sonderfall das *|* All das kann uns vorerst noch egal sein. Wir kommen im nächsten Teil dieses Tutorials noch mal darauf zurück.


Nur wollen wir die offensichtlich falsche Zeile korrigieren:
Einmal wollen wir den Hostnamen vor der IP Adresse haben und dort ist die IP Adresse auch noch fehlerhaft mit einem Komma statt einem Punkt notiert.


```
looser@computer:~/testdir> sed '#n
> /192/p
> ' testdata
computer.example.com 192.168.0.10
rechner.example.com 192.168.0.22
192.169,0.82  box.example.com
```

Wir können das mit einem sehr schwer lesbaren *sed* Befehl erledigen:


```
 sed -n 's/^\(19.\+\),\(.\+82\)[[:blank:]]\+\([[:alpha:]\.]\+$\)/\3 \1.\2/p' testdata
```

Oder sehr viel lesbarer.
Dazu brauchen wir noch:
*
Blöcke in sed* 
Mit geschweiften Klammern *{}* können wir *sed* Befehle gruppieren, so dass eine ganze Reihe von Befehlen auf einen Ausdruck/eine Adresse angewendet werden kann.
Das obige kaum mehr lesbare Beispiel schreibt sich viel verständlicher mit einem solchen Block und unter Verwendung von *-r*



```
#nr  <- Achtung" mit -r aufrufen!!!!
/119/                                        # wir adressieren mit /^19/ die Zeile, die mit "192" beginnt.
       {                                     # und öffnen einen Block an SED Anweisungen
         s/^(19.*82)[[:blank:]]+(.*)$/\2 \1/ # dann gruppieren wir die IP, lassen das Leerzeichen aus und gruppieren den Rest
                                             # und ersetzen zuerst den Hostnamen in \2 gefolgt von einem Leerzeichen dann \1, die IP
         s/,/./p                             # und zum Schluss korrigieren wir das Komma zu einem Punkt und drucken die Zeile
       }                                     # und der Block endet; diese Zeile ist erledigt. Für alle anderen Zeilen tut sed nichts.
```

Der Unterschied zwischen der nicht lesbaren und der gut lesbaren Lösung liegt in zwei wesentlichen Punkten. Bei der nicht lesbaren haben wir kein *-r* angegeben und müssen deshalb alle runden Klammern und den *+* Quantifikator mit Backslash escapen. Außerdem haben wir nur einen *s*ubstitute Befehl ohne Adressangabe. Also muss der RegEx selbst die Zeile eindeutig abbilden. Und wir müssen die IP-Adresse in zwei Gruppen aufteilen, um das Komma auslassen zu können. Später im Ersetzungsteil setzen wir zuerst den Hostnamen *\3* ein, dann folgt ein Leerzeichen, und dann der erste Teil der IP-Adresse. Danach kommt dann der buchstäbliche Punkt und der Rest der IP in *\2*.  

Damit kommen wir zum Ende des zweiten Teils. Mit den hier gezeigten Dingen kann man bereits alle alltäglichen Aufgaben mit *sed* erledigen.
Lest es ein paar Mal und übt mit den Testdaten. Rechtschreibfehler verbessern z.B.

Aber wir haben noch lange nicht den Überblick, was man mit *sed* alles anstellen kann. Wir haben bislang nur ein paar Befehle, verschiedene Schreibweisen, ein paar Schalter und Blöcke kennengelernt.
All das arbeitet nur auf einer gerade aktuell im *Patternspace* befindliche Zeile. So nennt man in *sed* den Puffer für die aktuell aus dem Stream gelesene Zeile. Es gibt aber auch noch einen anderen Puffer, den *Holdspace*. Und es gibt auch Sprungmarken und Verzweigungen.
Das wollen wir im dritten Teil des Tutorials beleuchten.
Aber, wie schon gesagt: Mit dem jetzigen Wissen könnt ihr schon viele Alltagsprobleme erschlagen.
*sed* ist rattenschnell und sieht ziemlich geekig aus. Und es kann ganze Verzeichnisbäume voll Dateien bearbeiten. Ein Buch, bei dem jedes Kapitel auf Unterverzeichnisse und viele Dateien verteilt ist, könnt ihr mit einem einzigen, geekigen *sed* Scriptchen konsistent ändern.

Es lohnt sich, das zu Lernen.
Wir werden im dritten Teil auch einige nützliche Scripte schreiben.
Und wenn jemand Vorschläge für Scripte hat, einfach mir eine Mail schreiben. (Bitte mit Beispieldaten).


_Dieses Minitutorial steht unter der Lizenz CC BY-NC-SA kann also nichtkommerziell weitergegeben werden unter den gleichen Bedingungen bei Nennung meiner Email karl.thomas.schmidt@googelmail.com_

----------

