Sed - letztes Vorkommen eines Strings

O

OnePixel

Hallo @All,

ich habe ein Problem mit sed und hoffe hier auf Hilfe bzw. Lösung meines Problems ;-)

zu meinem Probem:
Ich möchte in der "resolv.conf" einen nameserver hinzufügen, der unter dem letzten nameserver-EIntrag stehen soll. Ich wollte also nun mit sed
den letzten nameserver am Zeilenanfang suchen und unter dem eine Leerzeile einfügen und in einem weiteren sed Befehl den neuen nameserver eintragen.

Der zweite Befehl funktioniert auch jedoch kann ich mit sed nicht den ersten umsetzen (den letzten nameserver am Zeilenanfang suchen und eine Leerzeile unter diesem einfügen.

Der zweite Befehl sieht bei mir wie folgt aus:
cat /etc/resolv.conf | sed "s/^$/nameserver 999.999.99.9/" > /etc/resolv.conf

Die resolv.conf besitzt bei mir folgende Syntax:

domain meineDomain.com
nameserver 999.999.99.9
nameserver 888.888.88.8
nameserver 777.777.77.7
search meineDomain.com meinedomain.net


Die sed-Befehle sollen dann in ein sh script, welches auf verschiedenen Servern ausgeführt wird. Die Anzahl der nameserver variert. Über die Zeile kann man also leider nicht gehen.

Könnt ihr mir helfen?
Danke schon mal im vorraus.

Lieben Gruß
OnePixel
 
Hallo OnePixel,

probier mal folgendes Shell-Skript:
Bash:
#!/bin/sh

FILE="/etc/resolv.conf"
ENTRY="nameserver 666.666.66.6"

LINE=`sed -n '/^nameserver /=' "$FILE" | tail -n 1`
sed -i "${LINE}a${ENTRY}" "$FILE"

Grüße,
Matthias
 
ERSTMAL DANKE FÜR DIE SCHNELLE ANTWORT ;-)

habe es mal ausgeführt, jedoch mit folgender Fehlermeldung:
Code:
Syntax: tail [+/-[n][lbc][f]] [datei]
       tail [+/-[n][l][r|f]] [datei]
sed: Unzulässige Option -- i

Kann damit leider nichts anfangen....

habe selbst auch nochmal probiert:
mit folgendem Kommando bekomm ich eine Leerzeile unter allen Zeilen, die mit nameserver beginnen. Kennst du das Metazeichen, mit dem ich sage,
dass er nur das letzte Vorkommen von nameserver benutzen soll?
Code:
cat /etc/resolv.conf | sed '/^nameserver/G'

Habe gehofft das man nur noch nen .? an die richtige Stelle fixieren müsste..... ;-)

Danke schonmal
Lieben Gruß
OnePixel
 
ERSTMAL DANKE FÜR DIE SCHNELLE ANTWORT ;-)

habe es mal ausgeführt, jedoch mit folgender Fehlermeldung:
Code:
Syntax: tail [+/-[n][lbc][f]] [datei]
       tail [+/-[n][l][r|f]] [datei]
sed: Unzulässige Option -- i

Kann damit leider nichts anfangen....
Oh, da hab ich wohl ein paar GNU-Erweiterungen verwendet. Probier es mal so:
Code:
#!/bin/sh

FILE="/etc/resolv.conf"
ENTRY="nameserver 666.666.66.6"
TMPFILE="`tempfile`"

LINE=`sed -n '/^nameserver /=' "$FILE" | tail -1`
sed "${LINE}a${ENTRY}" "$FILE" >"$TMPFILE"
mv "$TMPFILE" "$FILE"
Das -i bei sed sollte dafür sorgen, dass die Datei in-place bearbeitet wird. Kann man aber auch mit cat erreichen. \edit: Quatsch. Man muss eine temporäre Datei verwenden, wie deepthroat weiter unten anmerkt. Habe das Skript mal ausgebessert.

habe selbst auch nochmal probiert:
mit folgendem Kommando bekomm ich eine Leerzeile unter allen Zeilen, die mit nameserver beginnen. Kennst du das Metazeichen, mit dem ich sage,
dass er nur das letzte Vorkommen von nameserver benutzen soll?
Ich bezweifle, dass das mit einem sed-Aufruf alleine funktioniert. sed arbeitet ja zeilenweise und man kann nicht feststellen, ob eine Zeile die letzte ihrer Art ist, ohne alle restlichen Zeilen durchzulaufen. Ich lasse mich da aber gerne eines besseren belehren, da ich kein Experte im Umgang mit sed bin.

Grüße,
Matthias
 
Zuletzt bearbeitet:
Hi.
Ich bezweifle, dass das mit einem sed-Aufruf alleine funktioniert. sed arbeitet ja zeilenweise und man kann nicht feststellen, ob eine Zeile die letzte ihrer Art ist, ohne alle restlichen Zeilen durchzulaufen. Ich lasse mich da aber gerne eines besseren belehren, da ich kein Experte im Umgang mit sed bin.
Na, wenn das keine Herausforderung ist. ;)

Code:
#!/bin/sed -nf

H

/^nameserver /{
  s/^.*$//
  x
  s/^\n//
  p
}

${
  i\
nameserver blablabla
  g
  s/^\n//
  p
}
Gruß
 
Zuletzt bearbeitet:
Hallo nochmal ;-)

also habe das Problem jetzt gelöst.
Meine Lösung:

RESOLV_CONF="/etc/resolv.conf"
AUSGABE_TAIL="`cat "${RESOLV_CONF}" | grep "nameserver" | tail -1`"

cat ${RESOLV_CONF} | sed "/${AUSGABE_TAIL}/G" | sed "s/^$/nameserver 333.33.333.3/" > ${RESOLV_CONF}

TADA :)

EInen riesen dank an euch ! Thanks a lot
Liebe Grüße
OnePixel
 
RESOLV_CONF="/etc/resolv.conf"
AUSGABE_TAIL="`cat "${RESOLV_CONF}" | grep "nameserver" | tail -1`"

cat ${RESOLV_CONF} | sed "/${AUSGABE_TAIL}/G" | sed "s/^$/nameserver 333.33.333.3/" > ${RESOLV_CONF}
Hast du das getestet? Normalerweise wird bei dieser Art Umleitung zuerstmal die Datei auf 0 Byte geschrumpft bevor cat überhaupt anfängt zu lesen. In der Regel ist das reine Glückssache falls es funktioniert.

Du mußt entweder die Datei erstmal komplett in den Speicher lesen (ist ja nicht so groß) oder temporäre Dateien verwenden.

Was für ein Betriebssystem verwendest du denn? Welche Shell?

Gruß

PS: Und bitte verwende die Code-Tags für deine Codeschnipsel!
 
Zuletzt bearbeitet:
^^
eine Reaktion von dir hatte ich schon befürchtet/erwartet ;-) Magst du vielleicht noch das Prinzip kurz erklären?
Ich dachte das wäre selbstdokumentierender Code?! ;)

Die grundlegende Vorgehensweise ist folgende:

Jede Zeile wird erstmal zum Hold-Space hinzugefügt (mit einem führenden Zeilenumbruch).

Wenn die Zeile mit nameserver beginnt, dann wird der Pattern-Space gelöscht und mit dem Hold-Space vertauscht und es werden alle bisher gelesenen Zeilen ausgegeben (ohne den führenden Zeilenumbruch).

Das wiederholt sich bis die Verarbeitung am Ende der Eingabe angekommen ist (die $ Adresse). Bisher wurde immer bis zum zuletzt gelesenen nameserver Eintrag schon alles ausgegeben und es ist auch kein solcher Eintrag mehr aufgetreten, also muss jetzt der neue Eintrag ausgegeben werden und dann noch der restliche Text aus dem Hold-Space (ohne führenden Zeilenumbruch).

Man sollte das ganze evlt. doch lieber komplett in Bash schreiben. :)
\edit: Der Backslash in der Zeile nameserver blablabla\ gehört aber weg, oder? Zumindest klappt es auf meinem System nur ohne.
Richtig, der Backslash muss weg. Oder nach dem Backslash muss noch ein Leerzeichen folgen, welches der Highlighter hier unterschlagen hat. (irgendwie hat mich da die Formulierung der info Seiten irritiert). Außerdem fällt mir gerade auf, das der d Befehl überflüssig ist.

Gruß
 
Zurück