[gelöst] sed: gesuchte zeile ersetzen

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
chris7
Beiträge: 22
Registriert: 29.04.2010 10:12:27

[gelöst] sed: gesuchte zeile ersetzen

Beitrag von chris7 » 25.02.2011 14:33:43

hi,
ich möchte in einer Datei nach einer bestimmtetn Formatierung suchen und diese dann durch einen bestimmten String ersetzen.
In der Datei kann z.B. folgendes stehen (die Zwischenräume sollen Leerzeichen und/oder Tabs sein können):

Code: Alles auswählen

#syntax bla
# syntax bla
 #syntax bla
 # syntax bla
syntax bla
 syntax bla
	sytanx	bla
	 syntax 	 bla
Ich hab ein wenig gegoogelt und hab mir folgende Zeile erdacht
sed -i "s/^[[:space:]#\t]*syntax[[:space:]\t]+.*/syntax on/g" filename
sie funktioniert aber nicht; was ist falsch?
mfg
chris
Zuletzt geändert von chris7 am 04.03.2011 17:58:26, insgesamt 1-mal geändert.

robi1
Beiträge: 13
Registriert: 27.12.2010 19:15:10

Re: sed: gesuchte zeile ersetzen

Beitrag von robi1 » 25.02.2011 15:48:53

Fang mal hiermit an, ich bin mir nicht sicher was du alles hinter "syntax" abfangen willst und was nicht.

Code: Alles auswählen

sed -e 's/^[ \t#]*syntax/syntax on/g' filename
eventuell suchst du das hier

Code: Alles auswählen

sed -n 's/^[ \t#]*syntax[ \t]\+/syntax on /p' filename
robi1

chris7
Beiträge: 22
Registriert: 29.04.2010 10:12:27

Re: sed: gesuchte zeile ersetzen

Beitrag von chris7 » 25.02.2011 16:43:18

danke,

Code: Alles auswählen

sed -i 's/^[ \|\t\|#]*syntax[ \ta-z]\+/syntax on/g' filename
funktioniert

wofür ist der Backslash hinter dem zweiten regulären Ausdruck (vor dem Plus)

Code: Alles auswählen

...syntax[ \ta-z]\+...
?

Wenn ich auch nur das erste Vorkommen ändern wollte, wie könnte ich das realisiern (erst mit grep die Zeile raussuchen?), da das g (oder die Zahl) die ans Ende gesetzt wird, bezieht sich doch nur auf das vorkommen in einer Zeile (oder)?

robi1
Beiträge: 13
Registriert: 27.12.2010 19:15:10

Re: sed: gesuchte zeile ersetzen

Beitrag von robi1 » 26.02.2011 00:26:45

chris7 hat geschrieben: wofür ist der Backslash hinter dem zweiten regulären Ausdruck (vor dem Plus)

Code: Alles auswählen

...syntax[ \ta-z]\+...
?
hinter "syntax" soll ein oder mehrere Leerzeichen oder Tabulatoren sein. und nicht etwa zB bei "syntaxhighlighting" auch treffen

Code: Alles auswählen

syntax[ \t]*
würde bedeuten es dürfen dort Null Mal oder beliebig viele solcher Zeichen sein. also auch das "syntaxhighlighting" würde gefunden.

Code: Alles auswählen

syntax[ \t]+
würde jedoch interpretiert das hinter "syntax" ein Leerzeichen oder Tabulator sein muss und anschließen ein "+"
also muss bei sed an dieser Stelle das "+" entwertet werden damit es seine Aufgabe erfüllt und das davorstehenden Ausdruck "mindestens 1 Mal" vorkommen zu lassen.

Ist bei sed immer ein bischen gewöhnungsbedürftig welche Zeichen man im regulären Ausdruck wo entwerten muss und wo nicht. Notfalls hilft ausprobierten und es hat niemand behauptet, reguläre Ausdrücke und sed ist was Einfaches.

chris7 hat geschrieben:Wenn ich auch nur das erste Vorkommen ändern wollte, wie könnte ich das realisiern (erst mit grep die Zeile raussuchen?)
wer die Befehle wie folgt oder ähnlich gruppiert "grep | sed" oder "grep | awk" outet sich immer sofort als Anfänger der von sed, grep und awk eingentlich überhaupt keine Ahnung hat.

es gibt bei sed dafür verschiedene Möglichkeiten, ich würde folgende vorschlagen, ist nicht die Schönste, doch wohl das was man am einfachsten erkären kann. :)

Code: Alles auswählen

sed -n '/^[ \t#]*syntax[ \t]\+/{s/^[ \t#]*syntax[ \t]\+/syntax on /p;q}' filename
Zur Erklärung:
sed -n '/^[ \t#]*syntax[ \t]\+/{s/^[ \t#]*syntax[ \t]\+/syntax on /p;q}' filename
Dieses ist eine Adressierung in Form eines Regulären Ausdruckes, es werden nur die Zeilen angesprochen die auch das enthalten, was dann geändet werden soll, alle anderen Zeilen werden ignoriert und gar nicht weiter bearbeitet.
sed -n '/^[ \t#]*syntax[ \t]\+/{s/^[ \t#]*syntax[ \t]\+/syntax on /p;q}' filename
Ausgeführt werden dann pro adressierter Zeile eine Gruppe von Befehlen, in diesem Fall 2 , der erste die Ersetzung mit der Ausgabe des Speichers, und dann als 2. Befehl wird sed beendet. Es kommt somit also nur der erste Treffer in der Datei zum Zuge, weil einfach der gesamte Sedbefehl schon nach dem ersten Treffer beendet wird.



Und nachdem das Prinzip dann klar ist, kann man das Ganze noch etwas verkürzen und optimieren,

Code: Alles auswählen

sed -n '/^[ \t#]*syntax[ \t]\+/{s//syntax on /p;q}' filename
in dem man beim s-Befehl einfach das Suchmuster wegläßt, sed nimmt dann an diese Stelle das Suchmuster der Adressierung.


Eine ganz andere Methode welche ohne den Abbruch des sed-Kommandos auskommt und somit es auch erlauben würde das mit sed in der Datei gleich selbst zu editieren und zwar jeweils nur den ersten Eintrag abzuändern könnte zB so hier aussehen. Mal ohne Erklärung.

Code: Alles auswählen

sed -ie '/^[ \t#]*syntax[ \t]\+/!b;s/^[ \t#]*syntax[ \t]\+/syntax on /; :append ;$!{n;b append}' filename

robi

Antworten