Re: Sed Verständnisproblem
Hallo Gebhard,
Gebhard Dettmar <gebhard.dettmar@student.hu-berlin.de>
wrote:
> On Thursday 08 September 2005 21:49, Frank Dietrich wrote:
> > Mein Vorschlag wäre:
> > sed -e ':x;s/\(.*[A-Za-z]\) \+\([a-z]\)/\1\2/g;tx'
> >
> > :x - setzt ein Label
> >
> > s/\(.*[A-Za-z]\) \+\([a-z]\) - findet "[A-Z] [a-z]" und
> > "[a-z] [a-z]", mit " " >=1 dazwischen,
> > durch das ".*"es wird immer nach dem am weitesten rechts
> > liegende Pattern gesucht
> > \1\2 - dürfte klar sein
> > tx - wird das angegebene Pattern gefunden wird am Label x
> > fortgesetzt
> >
> > Ich hoffe die Erklärung ist leicht verständlich. ;-)
>
> Nicht ganz. Das \+ (bzw. das Quoting vor dem +) verstehe ich nicht
Wurde von Mario schon erläutert.
> und die Erklärung zu Labels in der sed manpage ( Label for b and t
> commands???) auch nicht ;-(
Es wird sicher leichter verständlich wenn man die Anweisungen nicht
auf eine Zeile pappt sondern diese mittels einem Skript an sed
übergibt.
Angenommen Du sollst in einem Text "alle F O O B A R und FOOBAR in
Foobar wandeln.
Dann könnte man es in Pseudocode so lösen (dient nur als Beispiel,
und ist deshalb nur auf diesen einen Fall zugeschnitten):
- zuerst alle einzelnen Leerzeichen zwischen zwei Großbuchstaben
löschen
- dann alle FOOBAR durch Foobar ersetzen
# alle einzelnen Leerzeichen zwischen zwei Großbuchstaben löschen
echo "F O O B A R FOOBAR" | sed -e 's/\([A-Z]\) \([A-Z]\)/\1\2/g'
Das geht deswegen schief, weil sich die Zeile während der
Bearbeitung verkürzt.
Intern sieht das vereinfach so aus:
F O O B A R FOOBAR
|-- sed merkt sich diese Postion
FO O B A R FOOBAR
|-| das ist das nächste gefundene Pattern
|-- sed merkt sich diese Postion
FO OB A R FOOBAR
|-| das ist das nächste gefundene Pattern
FO OB AR FOOBAR
und das kommt als Ergebnis raus
Lösung bringt hier die mehrmalige Wiederholung des sed Kommandos.
Oder als Pseudocode:
- wiederhole solange bis das Pattern nicht mehr gefunden wird
Als Skript lässt sich das dann so schreiben:
--- sample.sed ---
:x -- Label x
s/\([A-Z]\) \([A-Z]\)/\1\2/g -- das auszuführende Kommando
t x -- wenn durch das s Kommando
etwas getauscht wurde, letzte
Zeile nochmal einlesen und
Abarbeitung bei Label x fortsetzen
ansonsten nächstes Kommando
abarbeiten
s/FOOBAR/Foobar/g -- ersetzt alle FOOBAR durch Foobar
------------------
Aufgerufen wird das dann so:
echo "F O O B A R FOOBAR" | sed -f sample.sed
Intern passiert dann folgendes:
Ausgangszeile
F O O B A R FOOBAR
nach dem ersten Durchlauf, enthält die Zeile
FO OB AR FOOBAR
da eine Ersetzung erfolgt ist wird mit dieser Zeile nochmal ein
Durchlauf gestartet, danach sieht die Zeile so aus
FOOBAR FOOBAR
da eine Ersetzung erfolgt ist ("O O" und "B A") wird mit dieser Zeile
nochmal ein Durchlauf gestartet
FOOBAR FOOBAR
nach diesem Durchlauf wurde keine Ersetzung mehr durchgeführt, d.h.
"t x" springt nicht mehr zum Label x und s/FOOBAR/Foobar/g wird
ausgeführt
Da es sich um ein relativ kurzes sed-Skript handelt kann man die
Kommandos auch mit ";" getrennt auf eine Zeile schreiben und sed mit
"-e" übergeben. Bei komplexeren Skripten leidet da natürlich die
Lesbarkeit und Fehler lassen sich auch nicht mehr so einfach finden.
Hoffe noch ein wenig Licht ins Dunkel gebracht zu haben.
Frank
--
If code looks clumsy, it can usually be better written. Clean code
is more easily maintainable and modifiable.
Reply to: