Ersetzen von Zeichen abhängig vom Vorkommen

HUE

Well-Known Member
Moin Moin,

ich habe eine Datei, bei der ich in jeder Zeile die Leerzeichen ersetzen möchte. Dieser Vorgang soll aber nur den Rest der Zeile betreffen, die durch ein besonderes Zeichen getrennt wird. Beispiel

Vorher:

Hallo liebe Community|Hallo lieber HUE

Nachher:

Hallo liebe Community|Hallo_lieber_HUE

Im Beispiel ersetze ich die Leerzeichen durch den Unterstrich nach dem Vorkommen des "|".

Als Lösung wäre mir ein Skript mit dem sed Editor am liebsten.

Ich danke für Eure Hilfe recht herzlich.

HUE
 
Hierfür ist awk prädestiniert. Insbesondere kann man diesem Trennzeichen für Spalten vorgeben vorgeben. Dies geschieht ganz am Anfang, bevor etwas eingelesen wird (BEGIN). Wir wählen hier | sowohl für die Eingabe (FS) als auch für die spätere Ausgabe (OFS). Zudem ersetzen (gsub) wir in der zweiten Spalte ($2) jedes Leerzeichen (/ /) durch Unterstrich ("_") und geben die Zeile wieder aus (print).
Code:
awk 'BEGIN { FS = OFS = "|" } { gsub(/ /, "_", $2); print }' $DATEI
Statt einen Dateinamen anzugeben, kannst du awk auch etwas auf der Standardeingabe füttern.
 
Hallo Tron,

die Lösung mit awk ist cool, ich hatte aber momentan den Fokus auf sed, da ich die Textdatei schon mit einer Menge sed- Befehle manipuliere.

Einen herzlichen Dank an Dich, weitere Lösungen sind natürlich willkommen.

HUE
 
Hallo Tron,

die Lösung mit awk ist cool, ich hatte aber momentan den Fokus auf sed, da ich die Textdatei schon mit einer Menge sed- Befehle manipuliere.

Einen herzlichen Dank an Dich, weitere Lösungen sind natürlich willkommen.

HUE
Das ist doch keine Begründung. Für jeden Job das richtige Werkzeug. Das ist in dem Fall einfach awk...
 
Hi HUE

mit GNU sed würde die Zeile so aussehen:
Code:
echo 'Hallo liebe Community|Hallo lieber HUE' | gsed -e 's/|/\n&/;h;s/.*\n//;y/ /_/;H;g;s/\n.*\n//'

Ausgabe wäre dann:
Hallo liebe Community|Hallo_lieber_HUE

mfg Hoschi
 
Code:
% printf 'Tron und lme haben recht|Wer immer das mal warten muss, tut mir leid\n' | sed -E 'h;s/(.*)\|(.*)/\1/;x;s/(.*)\|(.*)/\2/;y/ /_/;H;x;y/\n/|/'
Tron und lme haben recht|Wer_immer_das_mal_warten_muss,_tut_mir_leid
 
Hey worldi,

kannst du das etwas erläutern? Ich habe es gestern als "Übungsaufgaben" auch versucht und bin leider an einer Stelle nicht weitergekommen.

Das mit der Backreference am Anfang verstehe ich noch. Das du mit h und H irgendwelche Buffer bedienst weiß ich, aber verstehe es nicht ganz.
Könntest du die Befehlszeile einmal "aufdröseln"?

Gruß
Markus
 
Puh... :ugly:

tl;dr
Zeile für Zeile wird die gewünschte Ausgabe wird zuerst grob im hold space zusammengebastelt und anschließend bereinigt ausgegeben.

Zuerst bissel was zu sed... :belehren:
Die Doku erwähnt zwei sog. "spaces": pattern space und hold space. Frei übersetzt sind das Arbeitsbereich und Ablage. Eingelesene Zeilen kommen ohne ihren Zeilenumbruch in den Arbeitsbereich (und ersetzen in der Regel dessen bisherigen Inhalt). Ersetzungen (durch z.B. "s/.../" oder "y/.../") erfolgen immer im Arbeitsbereich.
Die Strichpunkte trennen einzelne Befehle. Nach Abarbeiten aller Befehle wird der Inhalt des Arbeitsbereichs, gefolgt von einem Zeilenumbruch, ausgegeben (außer sed wurde mit -n aufgerufen).

Dann ein paar evtl. unbekannte Befehle...
Code:
h      Kopiere den Inhalt des Arbeitsbereichs in die Ablage
x      Vertausche die Inhalte von Arbeitsbereich und Ablage
H      Erweitere den Inhalt der Ablage um
         einen Zeilenumbruch und den Inhalt des Arbeitsbereichs
y///   Ähnlich wie tr(1): "foobar" -> y/abcdef/123456/ -> "6oo21r"


So. Angenommen die Eingabe ist jetzt...
Code:
foo foo|bar bar\nmoo moo|har har\n

Lese Zeile ein    ->  Arbeitsbereich="foo foo|bar bar"   Ablage=""
h                 ->  Arbeitsbereich="foo foo|bar bar"   Ablage="foo foo|bar bar"
s/(.*)\|(.*)/\1/  ->  Arbeitsbereich="foo foo"           Ablage="foo foo|bar bar"
x                 ->  Arbeitsbereich="foo foo|bar bar"   Ablage="foo foo"
s/(.*)\|(.*)/\2/  ->  Arbeitsbereich="bar bar"           Ablage="foo foo"
y/ /_/            ->  Arbeitsbereich="bar_bar"           Ablage="foo foo"
H                 ->  Arbeitsbereich="bar_bar"           Ablage="foo foo\nbar_bar"
x                 ->  Arbeitsbereich="foo foo\nbar_bar"  Ablage="bar_bar"
y/\n/|/           ->  Arbeitsbereich="foo foo|bar_bar"   Ablage="bar_bar"
Gebe Arbeitsbereich und Zeilenumbruch aus

Lese Zeile ein    ->  Arbeitsbereich="moo moo|har har"   Ablage="bar_bar"
h                 ->  Arbeitsbereich="moo moo|har har"   Ablage="moo moo|har har"
...usw...


Fragen? :D

Edit: y///
Edit: tl;dr
 
Zuletzt bearbeitet:
Danke :)

Sehr ausführlich und auch sehr gut erklärt. Werde mir das nochmal im Nachgang anschauen und hoffentlich in die tägliche Arbeit übernehmen!

Hast du "Lesetips" für SED / AWK?
Gruß
Markus
 
Hallo worldi,

Du/Sie bist/sind einfach WORLDI- Klasse.

Herzlichen Dank für eine solche Erläuterung. Ich brauche dafür immer etwas länger.

Als Lesetipp habe ich von Helmut Herold 'awk und sed' als gebrauchtes Buch erworben.
Leider bin ich auch nicht immer in der Lage ein Fachbuch zu verstehen, da ist dann Deine Erläuterung einfach besser.

Danke nochmals an alle.

MfG

HUE
 
Gerne :)

@m4rkus
Hmm. Ne, nicht wirklich. Ich hab mich gestern "nur schnell mal" mittels man page und Google->Stackoverflow schlau gemacht, nachdem ich h0sch1s coole Lösung gesehen hatte.
 
Danke :)

Sehr ausführlich und auch sehr gut erklärt. Werde mir das nochmal im Nachgang anschauen und hoffentlich in die tägliche Arbeit übernehmen!

Hast du "Lesetips" für SED / AWK?
Gruß
Markus
Such mal nach "O'Reilly bookshelf" da ist ein AWK + SED Buch dabei.
 
Zurück
Oben