April 2014: Weitere Funktionen von sed

Autoren: Michael Gisbers und Christian Hesse

sed ist Thema bei den Lerninhalten der folgenden LPI Prüfung:

Nachdem wir den Stream Editor `sed` im ersten Artikel der Serie kennengelernt und an anschließend einen Crashkurs zu 'Regulären Ausdrücken' absolviert haben, wurde das Wissen im vorangegangenen Artikel kombiniert. In diesem letzten Teil der Serie lernen wir weitere Funktionen von `sed` kennen. Als Beispiel dient uns dieses Mal eine Konfigurationsdatei des DHCP-Servers. Sie ist unter dem Namen `dhcpd.conf` gespeichert und enthält die eine oder andere Unstimmigkeit.

option domain-name-servers 172.16.1.1;

subnet 172.16.1.0 netmask 255.255.255.0 {
      range 172.1.1.10 172.1.1.254;
   option broadcast-address 172.1.1.255;
 option routers 172.16.1.1;
    option time-servers 172.16.1.1;
   option lease-time 86400;
}

Im Artikel lassen wir `sed` den geänderten Dateiinhalt ausgeben, gehen aber davon aus, dass die Änderungen ebenfalls in die Datei geschrieben werden und damit beim nächsten Aufruf vorhanden sind. Dieses Verhalten erreichen wir mit der Kommandozeilenoption `-i`, die wir bereits im ersten Teil der Serie kennengelernt haben.

Bisher haben wir uns auf die 'Substitution' von Mustern im gesamten Text beschränkt. Dabei kann `sed` auch weiter eingeschränkt werden: Eine Ziffer vor dem Kommando gibt die Zeile an.

Hier korrigieren wir in der vierten Zeile die IP-Adresse des Adressbereichs:

user@linux ~ $ sed '4s/172\.1/172.16/g' < dhcpd.conf
option domain-name-servers 172.16.1.1;

subnet 172.16.1.0 netmask 255.255.255.0 {
      range 172.16.1.10 172.16.1.254;
   option broadcast-address 172.1.1.255;
 option routers 172.16.1.1;
    option time-servers 172.16.1.1;
   option lease-time 86400;
}

Alternativ erreichen wir dasselbe mit einem Pattern-Matching. Der Vorteil liegt auf der Hand: Diese Variante funktioniert auch dann noch, wenn sich die Zeile durch eine Einfügung verschiebt.

user@linux ~ $ sed '/range/ s/172\.1/172.16/g' < dhcpd.conf

Nun stellen wir fest, dass es in unserem Netzwerk keinen Zeitserver gibt, die Option `time-server` ist also nicht mehr notwendig und soll ersatzlos gelöscht werden. Dazu dient das Kommanto `delete`, kurz `d`:

user@linux ~ $ sed '/time-servers/d' < dhcpd.conf
option domain-name-servers 172.16.1.1;

subnet 172.16.1.0 netmask 255.255.255.0 {
      range 172.16.1.10 172.16.1.254;
   option broadcast-address 172.1.1.255;
 option routers 172.16.1.1;
   option lease-time 86400;
}

Dokumentation ist immer eine gute Sache. Mit dem Kommando `insert`, kurz `i`, fügen wir eine ganze Zeile vor dem betreffenden Muster ein.

user@linux ~ $ sed '/^subnet/i # Subnet block' < dhcpd.conf
option domain-name-servers 172.16.1.1;

# Subnet block
subnet 172.16.1.0 netmask 255.255.255.0 {
      range 172.16.1.10 172.16.1.254;
   option broadcast-address 172.1.1.255;
 option routers 172.16.1.1;
   option lease-time 86400;
}

Umgekehrt macht es das Kommando `append`, kurz `a`. Hier wird die Zeile nach dem Muster eingefügt. Der Backslash markiert den Anfang des Textes und ermöglicht damit führende Leerzeichen. Andernfalls interpretiert `sed` das erste druckbare Zeichen als erstes Zeichen.

user@linux ~ $ sed '/^subnet/a \ # Subnet block options' < dhcpd.conf
option domain-name-servers 172.16.1.1;

# Subnet block
subnet 172.16.1.0 netmask 255.255.255.0 {
 # Subnet block options
      range 172.16.1.10 172.16.1.254;
   option broadcast-address 172.1.1.255;
 option routers 172.16.1.1;
   option lease-time 86400;
}

Nun wollen wir eine Konfigurationsoption löschen und durch eine neue Zeile ersetzen. Auch dazu gibt uns `sed` mit dem Kommando `change`, kurz `c`, die Möglichkeit:

user@linux ~ $ sed '/lease-time/c \ option max-lease-time 86400;' < dhcpd.conf
option domain-name-servers 172.16.1.1;

# Subnet block
subnet 172.16.1.0 netmask 255.255.255.0 {
 # Subnet block options
      range 172.16.1.10 172.16.1.254;
   option broadcast-address 172.1.1.255;
 option routers 172.16.1.1;
 option max-lease-time 86400;
}

Der Stream Editor `sed` kann allerdings nicht nur mit einzelnen Zeilen, sondern auch mit Bereichen umgehen. Start und Ende der Bereichsdefinition werden von einem Komma getrennt. Das Dollarzeichen nimmt eine besondere Funktion ein und stellt die letzte Zeile, also das Ende der Datei, dar.

user@linux ~ $ sed '3,$s/^\s\+/\t/' < dhcpd.conf
option domain-name-servers 172.16.1.1;

# Subnet block
subnet 172.16.1.0 netmask 255.255.255.0 {
        # Subnet block options
        range 172.16.1.10 172.16.1.254;
        option broadcast-address 172.1.1.255;
        option routers 172.16.1.1;
        option max-lease-time 86400;
}

Hier hat `sed` von der dritten bis zur letzten Zeile alle führenden Leerzeichen durch ein Tab-Zeichen ersetzt und damit die Datei übersichtlicher formatiert. Und auch für diesen Zweck können Muster eingesetzt werden. Statt feste Zeilenangaben nutzen wir Muster, die Anfang und Ende eines Blocks treffen:

user@linux ~ $ sed '/^subnet/,/^}$/s/^\s\+/\t/' < dhcpd.conf

Hoffentlich hat Ihnen die Reihe zum Thema Stream Editor `sed` und `Reguläre Ausdrücke` gefallen. Die Möglichkeiten sind damit noch lange nicht erschöpft, vielleicht konnten wir Sie aber zum Ausprobieren animieren. Im nächsten Artikel werden wir uns dem Thema `ip` widmen und lernen, Netzwerkeinstellungen auf der Konsole vorzunehmen.