Sed

Aus Gentoo Linux Wiki

Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

[Bearbeiten] Einleitung

Dieser Artikel will eine kurze Einführung in elementare Funktionen von "sed" geben, ohne Anspruch auf Vollständigkeit zu erheben. Er wendet sich v.a. an sed-Anfänger. Meine Ausführungen beruhen auf sed-4.1.4-r1. sed ist in der Standard Gentoo-Installation bereits vorhanden. Hilfreich für das Verständnis des Artikels sind grundlegende Kenntnisse von "Regular Expressions". Neben vielen anspruchsvollen sed-Tutorials, die den Anfänger oft überfordern, gibt es ein gut nachvollziehbares und klar strukturiertes Tutorial, das ich nur empfehlen kann: http://www.grymoire.com/Unix/Sed.html

[Bearbeiten] Installation

Code: emerge von sed
emerge -av sys-apps/sed

[Bearbeiten] Erstellung einer Testdatei

Code: Testdatei erstellen
cat > sed-test.txt << EOF
Dies ist Zeile 1
Hier isst ein Fehler
Hier isst noch ein Frhler
Dies ist die vorletzte Zeile
Dies ist die letzte Zeile
EOF

[Bearbeiten] Grundlegendes zu sed

[Bearbeiten] Arbeitsweise von sed

sed arbeitet zeilenorientiert, d.h. es liest die Eingabedatei Zeile pro Zeile und wendet auf jede Zeile den bzw.die Befehle an. Eine Zeile endet dort, wo das Zeichen "linefeed", also 0x0A steht.

[Bearbeiten] Dateiübergabe an sed

Es gibt mehrere Möglichkeiten, die zu bearbeitende Datei an sed zu übergeben.

cat sed-test-txt | sed [anweisungen...] # Output von cat ist Input von sed
sed [anweisungen...] < sed-test.txt     # Umleitung von Stdin
sed [anweisungen...] sed-test.txt       # Dateiname als Kommandozeilenparamter

Die Ausgabe erfolgt nach Stdout, also auf den Bildschirm. Sie kann mittels Pipe-Symbol an andere Kommandos übergeben oder in eine Datei umgeleitet werden:

cat sed-test-txt | sed [anweisungen...] | less        # Stdout ist Stdin für "less"
cat sed-test-txt | sed [anweisungen...] > output.txt  # Umleitung in Datei

[Bearbeiten] Aufbau der sed-Anweisungen

Die Anweisungen sind für Anfänger gewöhnungsbedürftig. Aber wenn man ein paar grundlegende Dinge verstanden hat, ist es nicht schwierig. Die sed-Anweisungen werden i.A. von einfachen Hochkommas umschlossen.

sed 'anweisung' < sed-test.txt

sed kann mehrere Anweisungen in einem Durchgang abarbeiten. In diesem Falle muss jedem Befehl die Option "-e" vorangestellt werden. Wenn nur eine Anweisung abgearbeitet werden soll, kann man "-e" weglassen.

sed -e 'anweisung1' -e 'anweisung2' < sed-test.txt

möglich, aber etwas unübersichtlicher ist auch diese Form:

sed -e 'anweisung1; anweisung2' < sed-test.txt

In vielen sed-Anweisungen kommt das Zeichen '/' vor. Es ist ein Begrenzungszeichen, also ein "delimiter". Eine Regular Expression, also ein Suchausdruck, wird durch zwei Schrägstriche begrenzt. Im folgende kürze ich "Regular Expression" durch "RE" ab.

sed '/isst/' < sed-test.txt # unvollständige Anweisung
# sed durchsucht die Datei Zeile pro Zeile nach dem String "isst"
# die RE "isst" wird durch "/" am Anfang und Ende eingegrenzt.
# "/" ist also nichts anderes als ein Begrenzungszeichen, ähnlich wie Hochkommata

Die vorige Anweisung ist unvollständig, da sie nur aus der RE '/isst/' besteht. sed muss noch mitgeteilt werden, wie mit dem Suchergebnis zu verfahren ist. Hinter der durch die RE getroffenen Bereichsauswahl ist der Befehl anzugeben. Eine sed-Anweisung enthält also i.A. mindestens zwei Komponenten (die Bereichsauswahl kann in bestimmten Konstrukten fehlen):

a) Bereichsauswahl
   Auswahl der Zeilen, die bearbeitet werden sollen. Im vorigen Beispiel würde sich
   die Auswahl auf alle Zeilen beziehen, in denen "isst" vorkommt.
b) Befehl
   Was soll mit den ausgewählten Zeilen passieren? Der einfachste Befehl lautet
   "p" (print), er  gibt die selektierten Zeilen am Bildschirm aus.

Das vorige Beispiel wird vervollständigt:

sed '/isst/p' < sed-test.txt
# Durchsuchen der Datei nach Zeilen, die "isst" enthalten
# Die selektierten Zeilen werden am Bildschirm ausgegeben
# "/" umschließt die RE, hat also mit dem Befehl "p" nichts zu tun.

Leider liefert die sed-Anweisung ein unbefriedigendes Ergebnis, da alle Zeilen ausgegeben werden. Dies liegt an der Arbeitsweise von sed, auf die ich hier nicht näher eingehen will. Um das gewünschte Ergebnis zu erhalten, muss sed mit der Option "-n" aufgerufen werden:

sed -n '/isst/p' < sed-test.txt    # beim p-Befehl immer die Option "-n" verwenden!
# aufgrund der Option "-n" werden nur die Zeilen ausgegeben, in denen "isst" vorkommt.

Wenn man die Option "-e" verwendet (s.o.), muss beachtet weden, dass "-n" vor "-e" steht.

sed -n -e '/isst/p' < sed-test.txt # "-e" (s.o.) muss hinter "-n" stehen!

[Bearbeiten] explizite Bereichsauswahl

Im vorigen Kapitel wurde beschrieben, wie Zeilen aufgrund einer RE selektiert werden können. Es ist jedoch auch möglich, bestimmte Zeilen explizit auszuwählen, also z.B. "Zeile 1", "Zeile 1-2", "letzte Zeile" usw. In diesem Falle wird die Bereichsauswahl direkt angegeben, sie steht also nicht zwischen "/" wie bei RE-Ausdrücken. Der Befehl 'p' steht direkt hinter der Bereichsauswahl.

sed -n '1p' < sed-test.txt  # nur die erste Zeile ausgeben; Option "-n" nicht vergessen!
sed -n '$p' < sed-test.txt  # nur die letzte Zeile ausgeben

Wenn mehrere Zeilen selektiert werden sollen, werden Bereichsanfang und -ende durch ein Komma getrennt.

sed -n '1,2p' < sed-test.txt # Zeile 1-2 ausgeben

[Bearbeiten] Suchen und Ersetzen

Dies ist der häufigste Verwendungszweck von sed. Leider ist die Syntax zunächst etwas schwer zu durchschauen, aber Übung macht den Meister. In diesem Falle steht das Trennzeichen "/" an drei Stellen: vor und hinter der RE, also dem "Suchstring", und hinter dem Ersetzungsstring. Der mittlere Schrägstrich ist also Ende-Delimiter für die RE und gleichzeitig Anfangs-Delimiter für den Ersetzungsstring. Logischer Weise müsste der Schrägstrich vier mal vorkommen, aber sed hat die beiden mittleren Schrägstriche zu einem verschmolzen.

Beispiel: "isst" soll in allen Zeilen durch "ist" ersetzt werden

eigentlich müssten pro String ein Anfangs-/Ende-Delimiter verwendet werden.
/isst//ist/  # beide Strings müssten durch "/" begrenzt werden

sed verschmilzt die mittleren Schrägstriche zu einem!
/isst/ist/   # dies erscheint zunächst unlogisch.

Der Befehl "s" für "suchen & ersetzen" steht vor(!) der RE.

sed  's/isst/ist/' < sed-test.txt  # Befehl "s" steht am Anfang!
# sed selektiert alle Zeilen, in denen "isst" vorkommt, ersetzt "isst" durch "ist"
# und gibt das Ergebnis am Bildschirm aus

Um die Änderungen in die Datei zu schreiben, gibt es zwei Möglichkeiten.

a) mit Hilfe einer temporären Datei
sed  's/isst/ist/' < sed-test.txt  > sed-test2.txt # Ausgabe in temporäre Datei umleiten
vim sed-test2.txt                 # Ergebnis kontrollieren!
mv sed-test2.txt sed-test.txt     # Originaldatei ersetzen durch temporäre Datei
b) direkt
sed  -i 's/isst/ist/' sed-test.txt # Vorsicht, Änderungen werden direkt in Datei geschrieben!

Im Beispiel würde sed in jeder Zeile nur das erste gefundene "isst" durch "ist" ersetzen. Um zu erreichen, dass alle Fundstellen geändert werden, muss ans Ende der Anweisung der g-Spezifizierer (=global) gesetzt werden:

sed  's/isst/ist/g' < sed-test.txt

[Bearbeiten] selektives Suchen und Ersetzen

Beim "normalen" Suchen und Ersetzen werden alle Zeilen in den Suchvorgang einbezogen. Es kommt jedoch immer wieder vor, dass die Ersetzung nur innerhalb eines bestimmten Bereiches erfolgen soll. Die Bereichsauswahl kann, wie oben beschrieben, über eine RE oder explizit erfolgen.

Beispiel: Ans Ende aller Zeilen, in denen "isst" vorkommt, soll " --Fehler!" angehängt werden. Das normale Suchen und Ersetzen hilft hierbei nicht weiter, denn "isst" soll ja nicht ersetzt werden, sondern dient nur Selektion der Zeilen, an die das Suffix angehängt werden soll. Es sind also zwei Vorgänge erforderlich: (1) Bereichsauswahl über die RE "/isst/" (2) Suchen des Zeilenendes und ersetzen durch " --Fehler!". Genau genommen wird nicht das Zeilenende ersetzt, sondern ein gedachte fiktives "leer-Zeichen" (sozusagen "") vor dem Zeilenende. Damit sed weiß, dass sich Suchen und Ersetzen nur auf die Bereichsauswahl bezieht, steht es hinter der Bereichsauswahl in geschweiften Klammern. Sie können auch weggelassen werden. Ich rate jedoch dazu, sie zu verwenden, da die Logik des Befehls dadurch klarer wird.

sed '/isst/{s/$/ --Fehler!/}' < sed-test.txt
# /isst/           -> Bereichsauswahl über RE
# {...}            -> Anweisung in "{...}" bezieht sich auf die vorangestellte Bereichsauswahl
# $                -> Platzhalterzeichen für "Zeilenende" (in Suchen & Ersetzen Anweisungen)
# s/$/ --Fehler!/  -> fiktives "leer-Zeichen" vor dem Zeilenende wird ersetzt durch " --Fehler!"

Bei expliziter Bereichsauswahl funktioniert dies analog. Beispiel: Ans Ende der 2. und 3. Zeile soll " --Fehler!" gesetzt werden.

sed '2,3{s/$/ --Fehler!/}' < sed-test.txt
# 2,3   -> explizite Bereichsauswahl: Zeile 2-3

Beachten Sie, dass die explizite Bereichsauswahl durch keine Delimiterzeichen "/" eingegrenzt ist. Beispiel: Ans Ende der letzten Zeile soll " --Ende" gesetzt werden.

sed '${s/$/ --Fehler!/}' < sed-test.txt
# $  -> explizite Bereichsauswahl; "$" steht hier für "letzte Zeile"

Beispiel: an den Anfang der ersten Zeile soll "Anfang--" gesetzt werden.

sed '1{s/^/Anfang--/}' < sed-test.txt
# 1 -> explizite Bereichsauswahl
# ^ -> Platzhalterzeichen für "Zeilenanfang"
#      ein fiktives "leer-Zeichen" ("") am Zeilenanfang wird ersetzt durch "Anfang--"

Der vorige Befehl funktioniert auch ohne {}, ist aber schwerer zu lesen:

sed '1s/^/Anfang--/' < sed-test.txt

[Bearbeiten] delete-Befehl

Der delete-Befehl ist die Umkehrung des print-Befehls: Die bei der Bereichsauswahl (mittels RE oder explizit) selektierten Zeilen werden "gelöscht", also nicht ausgegeben.

sed  '/isst/d' < sed-test.txt  # Zeilen, die "isst" enthalten, werden nicht ausgegeben
sed  '3d'      < sed-test.txt  # die dritte Zeile wird nicht ausgegeben

[Bearbeiten] besondere Zeichen

[Bearbeiten] Negation

Das Zeichen "!" hinter der Bereichsauswahl bewirkt eine Negation.

sed  '/isst/!d' < sed-test.txt # Zeilen, die "isst" nicht enthalten, werden nicht ausgegeben
sed -n '1!p'    < sed-test.txt # alle Zeilen außer Zeile 1 werden ausgegeben

[Bearbeiten] $-Zeichen: letztes Element

Das $-Zeichen steht bei der Bereichsauswahl für "letzte Zeile":

sed -n '$p' < sed-test.txt # letzte Zeile ausgeben

In einer RE steht das $-Zeichen für "Zeilenende":

sed -n '/Zeile$/p' < sed-test.txt # Zeilen ausgeben, in denen "Zeile" am Ende steht

Möchte man dem Zeilenende eine Zeichenkette anhängen, genügt ein $ als Suchmuster:

sed -n 's/$/ und Schluss!/p' < sed-test.txt # Jede Zeile endet mit ' und Schluss!'

[Bearbeiten] ^-Zeichen

Das ^-Zeichen steht in einer RE für Zeilenanfang:

sed -n '/^Hier/p' < sed-test.txt # Zeilen ausgeben, in denen "Hier" am Anfang steht

Innerhalb einer character class in einer RE steht es für Verneinung.

sed -n '/F[^e]hler/p' < sed-test.txt 
# Zeilen ausgeben, in denen das Wort "F.hler" vorkommt, wobei der 2. Buchstabe kein "e" ist

Möchte man dem Zeilenanfang eine Zeichenkette voranstellen genügt ein ^ als Suchmuster:

sed -n 's/^/Am Anfang stand /p' < sed-test.txt # Jede Zeile beginnt mit 'Am Anfang stand '

[Bearbeiten] Control-Character

Mit Hilfe von sed können verschiedenste Konvertierungen durchgeführt werden, z.B. von DOS- (CR-LF) zu Unix Dateiendezeichen (LF). Control-Character können entweder als escape-character oder als hexadezimal-character dargestellt werden.

a) als escape-character
a="Zeile1\r\nZeile2"    # am Ende von Zeile1 steht CR-LF (=DOS-Zeilenende)
echo -e "$a" | cat -A 
# Inhalt wird inkl. Kontrollzeichen ausgegeben und darstellbar gemacht (cat -A)
# der carriage-return wird als ^M dargestellt (0x0D)
echo -e "$a"  | sed 's/\r//' | cat -A
# der carriage-return wird durch "leer" ersetzt, ^M wird nicht mehr angezeigt
unset a
b) als hexadezimal-character
a=$'Zeile1\x0d\x0aZeile2'  # am Ende von Zeile1 steht CR-LF (0x0d+0x0a)
echo -e "$a" | cat -A
echo -e "$a"  | sed 's/\x0d//' | cat -A 
unset a
wichtige control-character
Bezeichnung      escape   hex    "cat -A"
linefeed         \n       \x0a   $
carriage-return  \r       \x0d   ^M
tab              \t       \x09   ^I

Kontrollzeichen innerhalb von Variablen lassen sich auch sehr gut mit Hilfe des l-Befehls von sed am Bildschirm darstellen. Dies ist eine Alternative zu "cat -A"

a=$'Tabulator: \x09 CR: \x0d LF: \x0a'
echo -e "$a" | sed -n 'l'

[Bearbeiten] alternatives delimiter-Zeichen

Das delimiter-Zeichen "/" kann durch ein beliebiges anderes Zeichen ersetzt werden. Dies ist dann sinnvoll, wenn "/" innerhalb einer RE vorkommt, also z.B. bei einer Pfadangabe.

cat /etc/apache2/httpd.conf | sed 's@/var/www@/srv/www@' # "@" als delimiter-Zeichen

[Bearbeiten] Dateien ergänzen

Bisher ging es nur darum, den Inhalt einer Datei in selektierter bzw. geänderter Form ("suchen & ersetzen") auszugeben. Es ist jedoch auch möglich, eine Datei zu erweitern.

[Bearbeiten] Zeile am Dateianfang einfügen

Dies ist auch ohne sed möglich, z.B. mit Hilfe von echo und cat

cat - <<< "Anfang" sed-test.txt > sed-test2.txt
echo "Anfang" | cat - sed-test.txt > sed-test2.txt
echo "Anfang" > sed-test2.txt ; cat sed-test.txt >> sed-test2.txt

Mit Hilfe von sed geht dies eleganter.

sed '1iAnfang' < sed-test.txt > sed-test2.txt
# 1=Zeile 1 (explizite Bereichsauswahl)
# i=insert-Befehl

[Bearbeiten] Zeile innerhalb des Textes einfügen

Die folgende Anweisung fügt eine neue Zeile vor der vorletzten Zeile ein.

sed '/vorletzte/idies ist die vorvorletzte Zeile' < sed-test.txt > sed-test2.txt
# /vorletzte/ = Bereichsauswahl über RE
# i=insert-Befehl

[Bearbeiten] Zeile ans Dateiende anhängen

sed '$aEnde' < sed-test.txt > sed-test2.txt
# $=letzte Zeile (explizite Bereichsauswahl)
# a=append-Befehl

[Bearbeiten] Zeichen am Zeilenanfang einfügen

Das Zeichen "#" soll in allen Zeilen an den Zeilenanfang gesetzt werden.

sed 's/^/#/' < sed-test.txt
# s    =suchen & ersetzen
# /^/  ="Zeilenanfangszeichen"
# /#/  = Replace-String

Die Anweisung erscheint auf den ersten Blick nicht ganz logisch. Sie ist folgendermaßen zu interpretieren: Ersetze in jeder Zeile das am Zeilenanfang gedachte fiktive "leer-Zeichen" (sozusagen "") durch das #-Zeichen. Es wird also nicht der Zeilenanfang selbst ersetzt, was ja gar nicht möglich wäre, da es kein Zeilenanfangszeichen analog zum Zeilenendezeichen gibt. Einfacher verständlich wird die Anweisung, wenn man ein bestimmtes Wort am Zeilenanfang ersetzen lässt:

sed 's/^Hier/Dort/' < sed-test.txt # "Hier" am Zeilenanfang wird ersetzt durch "Dort"

Beispiel: Das Zeichen "#" soll bei Zeilen, die mit "Hier" beginnen an den Zeilenanfang gesetzt werden.

sed 's/^Hier/#Hier/' < sed-test.txt

Beispiel: Das Zeichen "#" soll in Zeilen, in denen "letzt" vorkommt, an den Zeilenanfang gesetzt werden. Dieser Fall unterscheidet sich von den vorigen, weil das "suchen & ersetzen" auf einen bestimmten Bereich beschränkt werden muss. Hierzu werden geschweifte Klammern verwendet.

sed '/letzt/{s/^/#/}' < sed-test.txt
# /letzt/   =RE; Zeilen, in denen "letzt" vorkommt, werden selektiert
# {s...}    = "suchen & ersetzen" wird nur in den selektierten Zeilen ausgeführt

[Bearbeiten] Verkettung mehrerer sed-Anweisungen

sed-Anweisungen lassen sich entweder mit Hilfe der Option "-e" aneinanderreihen oder mittels Pipe. Die Aneinanderreihung mittels Pipe macht v.a. dann Sinn, wenn die Auswahlmenge schrittweise reduziert werden soll, analog zum Aneinanderpipen von grep-Kommandos.

Beispiel: In der Datei httpd.conf sollen nur die Zeilen ausgegeben werden, die nicht mit "#" beginnen. Sodann soll "Allow" durch "Deny" ersetzt werden. Zunächst werden Zeilen selektiert, die nicht mit "#" beginnen. Die Ausgabe wird sodann mittels Pipe an einen weiteren sed-Prozess zu übergeben, der die Wortersetzung durchführt.

cat httpd.conf | sed -n '/^[^#]/p' | sed 's/Allow/Deny/'
# (1) Reduktion der Auswahlmenge
# (2) Ersetzung

Eine andere Möglichkeit besteht darin, mehrere Anweisungen an sed zu übergeben, die sukzessive abgearbeitet werden. Dies kann z.B. dann verwendet werden, wenn innerhalb einer Datei mehrere "Suchen & Ersetzen"-Befehle nacheinander durchgeführt werden sollen. Nach jedem s-Befehl werden sämtliche Zeilen ausgegeben, sodass beim folgenden s-Befehl wieder die gesamte Datei zur Verfügung steht.

Beispiel: in der Datei httpd.conf soll "Allow" durch "Deny" ersetzt werden und "localhost" durch "myserver"

cat httpd.conf | sed -e 's/Allow/Deny/g' -e 's/localhost/myserver/g'
(1) Ersetzung1
(2) Ersetzung2

Statt mehrere Anweisung mittels "-e" aneinanderzureihen, kann man diese auch durch ";" verketten, wobei das einfache Hochkomma nur am Anfang und am Ende stehen darf. Die Option "-e" kann hierbei weggelassen werden.

cat httpd.conf | sed 's/Allow/Deny/g; s/localhost/myserver/g'
# analog zur vorigen Anweisung

[Bearbeiten] Regular Expressions

Eine Regular Expression (im folgenden mit RE abgekürzt) ist so etwas wie ein Suchmuster, das dazu dient, komplizierte Suchanfragen mit wenigen Zeichen zu formulieren. Die Syntax ist standardisiert und wird von verschiedenen Programmen verstanden, z.B. sed, egrep, expr, perl. Das interpretierende Programm versucht, aus einer größeren Zeichenmenge (i.A. einer Zeile) eine Teilmenge zu finden, die zu der RE "passt". Oft gibt es mehrere Teilmengen, die passen. In diesem Fall wird die größte Teilmenge als Ergebnis verwendet.

[Bearbeiten] Platzhalterzeichen

Ein wichtiges Element der REs ist das Platzhalterzeichen ".". Es ist Platzhalter für jedes beliebige Zeichen, also numerische, alphabetische oder Sonderzeichen. Ein "." steht für ein einziges beliebiges Zeichen.

echo "ihr Name ist Mayer, sein Name ist Meier" | sed -n '/Ma.er/p'
# die RE "Ma.er" passt auf "Mayer", daher ist die Suchbedingung erfüllt.
# Nicht die Ergebnismenge "Mayer", sondern die ganz Zeile wird ausgeben.
echo "ihr Name ist Mayer, sein Name ist Meier" | sed -n '/M..er/p'
# "Mayer" und "Meier" passen, es gibt also 2 Ergebnismengen.
# Wie im ersten Fall wird die ganze Zeile ausgegeben.
# Die Anzahl der Ergebnismengen erfährt man nicht. 

Die Anzahl der Platzhalterzeichen lässt sich weiter spezifizieren. Leider müssen die geschweiften Klammern, "{" und "}" escaped werden durch Voranstellung des "\".

.\{n\}   # n mal "."
.\{,n\}  # 0-n mal "."
.\{n,\}  # n bis unendlich mal "."
.\{m,n\} # m-n mal "."
.*     # 0 bis unendlich mal "."
.\+     # 1 bis unendlich mal "."
.\?     # 0-1 mal "."
echo "ihr Name ist Mayer, sein Name ist Meier" | sed -n '/M.\{2\}er/p'
# die RE "M..er" ist identisch mit "M.\{2\}er"
# die Klammern müssen "escaped" werden, damit sed sie richtig interpretiert: \{...\}
echo "ihr Name ist Mayer, sein Name ist Meier" | sed -n '/M.*er/p'
# Es gibt mehrere Ergebnismengen:
# (1) Mayer
# (2) Mayer, sein Name ist Meier
# (3) Meier
# Es gilt (2), weil es die größte Ergebnismenge ist

Unabhängig davon, ob keine, eine oder mehrere Ergebnismengen gefunden werden, wird immer die gesamte Zeile ausgegeben. Wenn man nur die effektive (größte) Ergebnismenge sehen will, muss man egrep mit der "-o" Option zu Hilfe nehmen

echo "ihr Name ist Mayer, sein Name ist Meier" | egrep -o 'M.*er'
# Die RE steht anders als bei sed innerhalb von einfachen Hochkommta.
# -o bewirkt, dass nur die effektive Ergebnismenge angezeigt wird

Die effektive Ergebnismenge lässt sich auch durch den s-Befehl herausbekommen:

echo "ihr Name ist Mayer, sein Name ist Meier" | sed 's/M.*er/X/g'
# Beim Suchen & Ersetzen wird die effektive Ergebnismenge durch "X" ersetzt

[Bearbeiten] die einfachste RE

Die einfachste RE besteht aus einem Suchstring ohne weitere Deskriptoren, also z.B. dem Wort "Mayer".

echo "ihr Name ist Mayer, sein Name ist Meier" | sed  's/Mayer/X/g'
# "Mayer" ist effektive Ergebnismenge und wird durch "X" ersetzt

Beachten Sie, dass die folgende RE ein anderes Ergebnis liefert:

echo "ihr Name ist Mayer, sein Name ist Meier" | sed  's/.*Mayer.*/X/g'
# diese RE trifft auf die gesamte Zeile zu, nicht nur auf "Mayer"!

[Bearbeiten] REs beim "Suchen & Ersetzen"

Beim reinen s-Befehl werden immer alle Zeilen ausgegeben, unabhängig davon, ob Ersetzungen durchgeführt wurden oder nicht. Dies lässt sich ändern, indem man ihn mit dem p-Befehl kombiniert. Die Abläufe sind wie folgt:

a) p-Befehl
echo "dies wird nicht ausgegeben" | sed -n '/.*diiss.*/p'
# (1) gibt es eine Ergebnismenge, die zur RE "passt"?
# (2) wenn ja, gibt die ganze Zeile aus.
b) s-Befehl ohne p-Befehl
echo "dies wird ausgegeben" | sed 's/wird/wird immer/'
# (1) gibt es eine Ergebnismenge, die zur RE "passt"?
# (2) wenn ja, welches ist die effektive Ergebnismenge?
# (3) ersetze diese durch den Replace-String
# (4) gib die ganze Zeile aus (egal, ob geändert oder nicht)
c) s-Befehl mit p-Befehl
echo -e "xxx\nnächste Zeile" | sed -n 's/xxx/Ausgabe/p'
# Die Kombination von s- und p-Befehl bewirkt, dass
# nur die geänderten Zeilen ausgegeben werden.
# Die Option -n darf nicht vergessen werden.

Im Allgemeinen ist es sinnvoll, den g-Spezifizierer ("global") zu verwenden, der direkt vor oder hinter dem p-Befehl steht:

echo -e "xxx--xxx\nnächste Zeile" | sed -n 's/xxx/Ausgabe/pg'
# alle "xxx" werden ersetzt

[Bearbeiten] Character Classes

Eine Character Class definiert einen Zeichenvorrat. Sie besteht aus einer Menge von ein oder mehreren Zeichen und wird innerhalb von eckigen Klammern angegeben. Die Reihenfolge der Zeichen ist beliebig.

Beispiele:

[ae]           -> Zeichenvorrat besteht nur aus "a" und "e"
[aeiou]       -> alle Vokale in Kleinbuchstaben
[aeiouAEIOU]  -> ...in Klein- und Großbuchstaben
[a-fh-k]      -> Buchstaben a-f und h-k
[^a]          -> alle Zeichen außer "a"
[^abc]        -> alle Zeichen außer "a", "b" oder "c" (Reihenfolge egal!)

Es gibt bereits vordefinierte Klassen (POSIX-classes), die zwecks einfacherer Darstellung verwendet werden können:

POSIX classes
[:upper:]  [A-Z]  Großbuchstaben
[:lower:]  [a-z]  Kleinbuchstaben
[:alpha:]  [A-Za-z]  beides
[:alnum:]  [A-Za-z0-9]  Ziffern und Groß-/Kleinbuchstaben
[:digit:]  [0-9]  Ziffern
[:xdigit:]  [0-9A-Fa-f]  hexadezimal Ziffern
[:punct:]  [.,!?:.]  Punkt-Zeichen
[:blank:]  [ \t] "Whitespace" (Blank oder Space)
[:space:]  [ \t\n\r\f\v]  Blank
[:cntrl:]  Kontrollzeichen
[:graph:]  [^ \t\n\r\f\v]  Druckbare Zeichen ohne Space
[:print:]  [^\t\n\r\f\v]  Druckbare Zeichen mit Space

Beispiel: Die Buchstaben "y" und "i" sollen durch "xx" ersetzt werden.

echo -e "Mayer\nMaier\nMeyer\nMeier" | sed  's/[yi]/xx/'

Beachten Sie, dass beim Suchen und Ersetzen immer alle Zeilen komplett ausgegeben werden, unabhängig davon ob Ersetzungen durchgeführt wurden oder nicht. Daher lassen sich mehrere Suchen und Ersetzen Anweisungen gut aneinanderreihen.

Beispiel: "i" und "y" sollen durch "ii" ersetzt werden, sodann "a" und "e" durch "oo"

echo -e "Mayer\nMaier\nMeyer\nMeier" | sed  -e 's/[iy]/ii/g' -e 's/[ae]/oo/g'  # "Mooiioor"

[Bearbeiten] Bezugnahme auf die Ergebnismenge

Bei den bisherigen Anweisungen wurde der gesamte Zeileninhalt ausgegeben. Es gibt jedoch die Möglichkeit, direkt auf die effektive Ergebnismenge oder einen Teil daraus Bezug zu nehmen. Die hierfür erforderliche s-Anweisung führt kein Suchen und Ersetzen durch, sondern durchsucht den Datenstrom anhand der RE und bildet aufgrund des Ausdrucks in () nochmals eine Teilmenge, die ausgegeben werden kann.

Beispiel: Aus der folgenden Zeile soll nur das Element "blau" ausgegeben werden.

echo "-rot-blau-gelb" | sed 's/.*\(blau\).*/\1/g'
Die gesamte RE lautet: /.*blau.*/

Es soll jedoch nur der Teil der Ergebnismenge ausgegeben werden, der "blau" enthält. Folglich ist "blau" in runde Klammern zu setzen.

/.*\(blau\).*/
echo "-rot-blau-gelb" | sed 's/.*\(blau\).*/\1/g'
# s      -> "Suchen und Ersetzen", wobei kein "Ersetzen" durchgeführt wird
# .*     -> Beginn der RE: beliebiges Zeichen 0-n mal
# \(blau\) -> "blau" soll, falls es sich aus der Ergebnismenge extrahieren läßt, ausgegeben werden
# .*       -> Ende der RE: beliebiges Zeichen 0-n mal
# \1       -> die Ergebnismenge der 1. geklammerten RE wird ausgegeben
#             bei mehreren REs, wird jeder RE eine Zahl zugeordnet: \1 = 1.RE  \2 = 2.RE usw.


[Bearbeiten] oder-Verknüpfung mehrerer REs

echo "--rot--gelb--" | sed  's/\(gelb\|rot\)/x/g'
echo "--rot--gelb--" | sed  's/gelb\|rot/x/g'  
# die runden Klammern und das oder-Zeichen "|" müssen escaped werden
# die runden Klammern können weggelassen werden


SK, Ostfildern, den 15.7.2006

'Persönliche Werkzeuge
Andere Sprachen