Mit sed Zeilen mit Erkennungsmuster in Zeile von ... bis löschen

Hinweis: In dem Thema Mit sed Zeilen mit Erkennungsmuster in Zeile von ... bis löschen gibt es 10 Antworten auf 2 Seiten. Der letzte Beitrag () befindet sich auf der letzten Seite.
  • Hallo zusammen,


    ich überführe gerade die Adressen meiner Partnerin von Apple auf Linux. Aufgrund der vorherigen Datenlage und des Export - Import - Geschehens habe ich jetzt eine .vcf-Datei mit knapp 1400 Addressen.

    Darin sind sowohl viele Adressen doppelt und mehrfach vorhanden als auch in den Einträgen einzelner Adressen jeweils einzelne Zeilen.

    Ich bin dabei ein Script zu schreiben das das bereinigt.

    Der erste Schritt ist dabei das Löschen von Duplikatzeilen eines Eintrags. Das sollte mit sed gut gehen.

    Da aber z.B. die Telefonnummer von Axel auch bei Berta nochmal stehen kann soll sed jeweils nur die Zeilen m bis n bearbeiten, eben Axels Eintrag (mit readarray ermittelt).


    Ich bin Anfänger im scripten. Über RegExp habe ich vor ein paar Wochen mit Begeisterung gelesen und bin von den Möglichkeiten grundsätzlich begeistert, aber Können ist etwas gaanz anderes.

    Ich hab jetzt einige Stunden probiert (irgendwann auch mit for - do - done, aber letztlich viel zu umständlich und andere Fehlerquellen), muss mich aber geschlagen geben.


    Textteile zu ersetzen funktioniert mit z.B. sed -i '1,8s/alt/neu/g' ./datei.

    Will ich löschen mit sed -i '1,8d/alt/neu/g' ./datei  dann bekomme ich sed: -e Ausdruck #1, Zeichen 5: Zusätzliche Zeichen nach dem Befehl:

    Code
    frank@7470tw:~/bin/add> sed -i '1,8d/tee/neu/g' ./vb
    sed: -e Ausdruck #1, Zeichen 5: Zusätzliche Zeichen nach dem Befehl
    frank@7470tw:~/bin/add>

    Versuche ich sed -i '1,8/tee/neu/d' ./vb wird mir sed: -e Ausdruck #1, Zeichen 4: Unbekannter Befehl: »/« gemeldet:

    Code
    frank@7470tw:~/bin/add> sed -i '1,8/tee/neu/d' ./vb
    sed: -e Ausdruck #1, Zeichen 4: Unbekannter Befehl: »/«
    frank@7470tw:~/bin/add>


    Mir schwirrt der Kopf vor lauter RegExp-Leseversuchen auf verschiedensten Seiten... und mit try-and-error habe ich wohl alle Iterationen durch.

    Wo mache ich den Fehler?


    Nachtrag: Alle Iterationen bis auf die Richte wohl... :wacko:

    Dell Latitude 7470, 4 x i7 6600U, 32 GB, 1TB NVMe

    Tumbleweed, KDE Plasma

    Für den Inhalt des Beitrages 280527 haftet ausdrücklich der jeweilige Autor: baumkraxler

  • hab ich falsch gefragt...?

    Ne, hast du nicht.

    Ist halt nur nicht für jeden leicht zu beantworten.

    Was aber evtl. helfen könnte:

    Stell dich mal vor einen Spiegel und rufe 3x hintereinander den Namen "Berichtigung".

    Wenn er dann erscheint, wird er dir bestimmt einen Denkanstoß geben, um dich lediglich in die richtige Richtung zu lenken ;)

    Für den Inhalt des Beitrages 280711 haftet ausdrücklich der jeweilige Autor: sterun

  • Danke.

    Update: Habe einen Hinweis gefunden.

    Hier steht Eine Adresse ist zum Beispiel eine fixe Zeilennummer in der Eingabe oder ganze Bereiche, oder aber Zeilen, die auf einen bestimmten regulären Ausdruck passen.

    Man beachte es heißt "oder".

    Hab ich "überlesen", bzw. habe ich nicht erwartet daß genau diese Kombination nicht funktioniert...

    Es funktioniert mit sed -n -e 'zeilevon,zeilebisp' eingabedatei | sed -e  '/matchstring/d' > ausgabe.txt .

    Stell dich mal vor einen Spiegel und rufe 3x hintereinander den Namen "Berichtigung".

    Falls es doch ein workaround ist und es also eleganter geht bin ich dennoch dankbar für mögliche Hinweise.

    Hab ich gemacht, mal sehen...

    ... ansonsten markiere ich hier demnächst als erledigt. :thumbup:

    Dell Latitude 7470, 4 x i7 6600U, 32 GB, 1TB NVMe

    Tumbleweed, KDE Plasma

    Für den Inhalt des Beitrages 280713 haftet ausdrücklich der jeweilige Autor: baumkraxler

  • Erst mal ein guter Rat: Verwende niemals die Option -i, jedenfalls nicht bis du den großen SED- Rettungsschwimmerschein forensisch sicher nachweisbar verdient hast.

    Die Option -i meint "inline" - weshalb sed dann die Originaldatei in eine Temp- Datei kopiert, mit der es dann die Originaldatei mit den bearbeiteten Daten überschreibt.


    Bevor ich mich zu deinem Problem und deinen Verständnisschwierigkeiten sinnvoll äußere würde ich gerne wissen, was der Satz

    Darin sind sowohl viele Adressen doppelt und mehrfach vorhanden als auch in den Einträgen einzelner Adressen jeweils einzelne Zeilen.

    bedeuten soll. Welche einzelnen Zeilen sind innerhalb einer Adresse wie enthalten?


    Poste doch bitte einen Ausschnitt dieser Daten (die du gerne vorher anonymisieren kannst), damit wir ein Beispiel sehen, was du wirklich erreichen möchtest.


    Generell arbeite sed sehr einfach: Es liest eine angegebene Datei (oder aus einer Pipe) zeilenweise und wendet jede Anweisung des "sed- Programms" auf jede Zeile an.

    That's all.

    Dabei trennt ein Semikolon oder ein \n die sed-Befehle.

    Ähnlich, wie bei awk kann eine Anweisung aus einer Adressangabe und einer Aktion bestehen.

    Ein 3d löscht die dritte Zeile, oder ein /hugo/d löscht alle Zeilen, die die Zeichenkette hugo beinhalten.


    Eine Adressangabe kann also eine absolute Zeilennummer oder ein Suchbegriff - ein Regex - sein, der als syntaktische Kennzeichnung von zwei Slashes eingegrenzt wird.

    Natürlich kannst du auch Adressbereiche angeben. Das Format ist ebenfalls schlicht: Startadresse, Endadresse. Und selbstverständlich können beide Adressen sowohl eine absolute Zeilenadresse sein, oder wiederum Regexes, oder Mischungen dieser beiden Formen.


    Deine Fehlermeldungen rühren schlicht aus einem syntaktischen Mistverständnis®™ her:

    sed -i '1,8s/alt/neu/g' ./datei

    Das funktioniert klar: streameditiere mir die Datei ./datei und substituiere mir -inline /alt/ mit neu/.

    Und ebenso klar funktioniert nicht das hier:

    sed -i '1,8d/alt/neu/g' ./datei

    Denn hier sagst du ja: streameditiere mir die Datei ./datei und delete mir die Zeilen von Zeile 1 bis Zeile 8 .

    Jetzt wird es für sed richtig gruselig:

    Eigentlich müsste jetzt eine neuen Zeile oder ein Semikolon kommen. Der Delete- Befehl war ja klar und ist erledigt. Aber es kommt jetzt - wir sind in dem nächsten anzuwendenden Befehl - einen Adresse /alt/neu/. Das ist aber weder eine Adresse, noch ein Adressbereich (dafür müsste nach Abschluss des Regexes ein Komma kommen).

    Und danach steht noch ein völlig demotiviertes, syntaktisch unmögliches g .

    sed quittiert das exakt so:

    Zeichen 5: Zusätzliche Zeichen nach dem Befehl

    Denn nach dem delete Befehl kommt aus Sicht von sed nur noch Unsinn.


    Ähnlich deine zweite Fehlermeldung. Mit:

    sed -i '1,8/tee/neu/d' ./vb

    sagst du ja:

    streameditiere mir die Datei ./vb und für den Adressbereich von Zeile 1, bis Zeile 8 führe mir den Befehl ... äh, ja was denn? Jetzt kommt wieder kein Befehl (der kommen müsste), sondern ein syntaktisch voll vergeigter substitute Befehl, der jetzt auch noch eine Option d verwendet, die es nicht gibt.


    Es gibt immer nur [startAdresse[,endAdresse]]Befehl

    Oder eben ganze Blöcke von Befehlen.

    Für die Zeile, die "Anfang" beinhaltet bis hin zu Zeile Nummer 82 führe den Block an Anweisungen aus, schreibt man dann;

    sed -rn '/Anfang/,82{Anweisung1; Anweisung2; Anweisung3}' /some/path/to/somefile


    Es wäre wirklich hilfreich, wenn du anonymisierte Beispieldaten posten würdest. Dann könnte man das leicht schreiben.

    Es mag dir aber helfen, wenn du einfach dein sed- Script so bastelst, dass du die Duplikate einfach nicht mit sed zu erschlagen versuchst, sondern in einer Pipe mit sort|uniq erledigst.

  • Vielen Dank!!!

    Da ist nun ein wenig Erleuchtung auf mich über gesprungen. Daß nach dem Löschen der Zeilen nix übrig ist leuchtet ja nun ein. Wenn sich ein Scripting- und RegEx-Anfänger wie ich Stunden durchliest und rumprobiert stellt sich halt manchmal Betriebsblindheit ein. Aber Deine Aufdröselung anhand meiner Versuche gibt einen echten Lernerfolg.

    Erst mal ein guter Rat: Verwende niemals die Option -i, jedenfalls nicht bis du den großen SED- Rettungsschwimmerschein forensisch sicher nachweisbar verdient hast.

    Jau, ich arbeite ja zunächst mal nur mit Dummie-Dateien (Auszüge aus dem Original) und selbst die gibt es in Sicherungskopie. Schien mir erst mal eine elegante Lösung. Momentan bin ich eher auf dem Weg, eine neue Datei mit dem gewünschten Ergebnis zu erstellen.

    Deine Fehlermeldungen rühren schlicht aus einem syntaktischen Mistverständnis®™ her:

    Völlig richtig, siehe oben.

    der jetzt auch noch eine Option d verwendet, die es nicht gibt

    Das war mir nicht so klar, daß hier nur Optionen stehen, weil es p wohl sowohl als Befehl als auch als Option gibt.

    Poste doch bitte einen Ausschnitt dieser Daten (die du gerne vorher anonymisieren kannst), damit wir ein Beispiel sehen, was du wirklich erreichen möchtest.

    Da mache ich mich gleich dran, folgt in Kürze.

    Es mag dir aber helfen, wenn du einfach dein sed- Script so bastelst, dass du die Duplikate einfach nicht mit sed zu erschlagen versuchst, sondern in einer Pipe mit sort|uniq erledigst.

    Hhmmm..., zwei für mich neue Befehle, mal sehen...


    Ich erwurstele jetzt mal eine Beispieldatei, aus der die Anforderungen ersichtlich werden und einen Abriss meiner geplanten Herangehensweise und bin dann sehr gespannt, ob Anregungen für eine "sauelegante" Lösung kommen. Bei mir ist das noch recht umfangreich.


    Freue mich jedenfalls sehr über eure Hilfe!

    Dell Latitude 7470, 4 x i7 6600U, 32 GB, 1TB NVMe

    Tumbleweed, KDE Plasma

    Für den Inhalt des Beitrages 280724 haftet ausdrücklich der jeweilige Autor: baumkraxler

  • Hier ein Auszug aus der Ursprungsdatei:

    Ich weiß nicht, wie man das hier ändern kann, wenn man den Inhalt als .vcf-Datei mit Kate öffnet wird es übersichtlicher, es hat Farbgebung und Zeilennummern.

    Vielleicht gibt es Besseres als Kate, ich tu erst mal damit, probiere gerne etwas Anderes wenn es nicht zu viel extra Lernaufwand bedeutet (vi), habe nur begrenzte Hirnkapazität.


    Zeilen 1-11: Erich Sedmich, doppelter Telefonbucheintrag in Zeilen 7 und 8.


    Zeilen 28-41: Nochmal Erich Sedmich, mit einem Eintrag (Adresse, Zeile 34 und 35) der im ersten Datensatz fehlt, dort also ergänzt werden soll.

    Zeile 30, EMAIL, ist anders, soll also auch übernommen werden. Was dann beim Import in Adressprogramm passiert... ausprobieren.

    Die Übrigen Einträge (teils wieder doppelt) sind im ersten Datensatz schon da. PRODID wird vrsstl. willkürlich geändert, UID reicht eine, X-ABUID-ABUID ist

    rein Apple-spezifisch und wird erst mal eine übernommen, wahrscheinlich mittelfristig gelöscht.


    Zeilen 12-27: Erika Undmia. Telefonnummer (Z. 23-24) doppelt. Zeile 20, NOTE: Notiz ist mehrfach vorhanden in einer Zeile (dieses Detail ist aber nachrangig)


    Weiteres Feature: In der Originaldatei sind bei einigen Datensätzen Photos eingebettet, das hab ich grad nicht greifbar, Format in etwa:

    Code
    PHOTO:TYPE="JPEG,jpeg":9n/4ca10/31fß0oqnsbdjs-mveglwfnqefkn...  usw....
    .... usw, kann gut einige 100 Zeilen umfassen, ein Bild eben......
    * edit: Handschriftlich erstellt *

    Die Bilder mit zu nehmen habe ich mir für später im Projekt aufgehoben.


    Mein Ansatz ist im Moment die ganze Datei zeilenweise in ein Array einzulesen, parallel dazu Indexdateien für die Zeilennummern der Einträge BEGIN:VCARD, FN: (als Identifier) und END:VCARD zu erstellen.

    Dann wird Datensatz 1 abgearbeitet: Erich Sedmich. Zeile für Zeile in neue Datei schreiben, sofern nicht doppelt. Weitere Erich Sedmich suchen. Aus diesen Datensätzen jeweils das in die neue Datei schreiben, was wiederum nicht doppelt ist (in Bezug auf beide bzw. alle Datensätze).

    Die eingebetteten Photos laufen da im Grunde mit, habe ich nur für mich erst mal zurück gestellt bis ich ein wenig "besser" bin.

    Die in einer Zeile mehrfach vorhandenen Notizen (NOTE:) sind erstens nicht der Kern des Anliegens und, so ich vermute, zudem mit wenigen Befehlen zu bereinigen... hier vermute ich nur eine für mich schwer zu erstellende RegEx-Syntax, weshalb ich das auch zunächst zurück stelle, bis ich mehr drin bin.


    Ein Freund hat mal zu mir gesagt: "Du bist auch ein Perfektionierer...", womit er recht hat.

    Ich habe Lust bekommen, ein Script zu schreiben das man zur Verfügung stellen kann.

    Der hier angedeutete Datenwust entstand aus dem Export von einem Apple. Die lokal und bei iCloud gespeicherten Daten waren nicht zu unterscheiden, bzw. war nicht klar welche nur hier, welche nur da, welche hier und da gespeichert sind, also Alle genommen, was die doppelten Namenseinträge erklärt. Nicht perfekte Datenhygiene, dürfte aber nicht selten sein.

    Warum einzelne Felder (z.B. "TEL;", "ADR;" ) noch mehrfach vorkommen ist nicht klar, aber ist so. Exportvorgang?

    Auch auf einem Handy (Adressen im internen Speicher und/oder auf SIM-Card) kann es Wust geben, oder in der Synchronisierung zwischen Handy und Rechner, mit Sicherungsdateien...

    Da der Aufbau der VCARD-Dateien insgesamt einfach erscheint sollte ein Script das in > 90% der Fälle brauchbare Ergebnisse liefert, nicht allzuallzu schwierig sein (... na gut, ich bin halt optimistisch).


    Das würde mir Spaß machen, aber da brauche ich Hilfe für.

    Ich habe 9h verbracht mit sed zu spielen und heraus zu finden, daß Leerzeichen in Variablen nicht funktionieren. Das ist toll zum Lernen, aber ich kann oft auch schnell lernen und gerne auch etwas drumherum.

    Grundsätzlicher Ansatz, alternative Befehle die einfacher und / oder schneller sind oder eine effektivere, schönere Herangehensweise ermöglichen, einfaches Logging, gute Doku etcetc.


    Wäre das hier möglich / erwünscht (mein Favorit, wäre einfacher :whistling:) oder gäbe es dafür andere Lokalitäten?

    Ich denke, letztlich krägte ich das schon irgendwie hin, aber mehr Spaß hätte ich an der "schönen Lösung", mit Unterstützung.


    Jupp, lange geworden, bin gespannt.

    Dell Latitude 7470, 4 x i7 6600U, 32 GB, 1TB NVMe

    Tumbleweed, KDE Plasma

    Für den Inhalt des Beitrages 280728 haftet ausdrücklich der jeweilige Autor: baumkraxler

  • Der s- Befehl von sed ist der einzige, der solche Optionen kennt.

    Es gilt immer das Format [adresse|startAdresse,endAdresse]Befehl|{Befehlsblock}

    Für den s-Befehl ist das Format: s/Regex/Ersetzungsstring/Option(en)


    Für dein Problem solltest du awk verwenden. Damit lässt sich das alles elegant erschlagen.

    (awk ist ein Akronym aus den Namen der drei Programmierer, die diesen Befehl als erstes verbrochen haben: Aho, Weinberger und Kernighan, die Unixurgesteine. Es ist der einzige Befehl, der keinen mnemonischen Namen hat (soweit ich weiß))


    awk ist aus sed abgeleitet und folgt deshalb dem genau gleichen Schema, bietet aber sehr viel mehr, als sed. Man kann eigene Funktionen definieren, präzise Floatingpoint Numerik betrieben und noch manches mehr. Es beherrscht außerdem assoziative Arrays, die hier einiges erleichtern können.


    Insgesamt ist das aber kein triviales Problem.

    Es gibt, wie schon der VERSION- String zeigt, diverse Versionen von V-Cards, die dann auch noch auf verschiedenen Systemen nicht einheitlich implementiert werden.

    Willst du das für 90% aller Fälle abfangen, so ist das schon eine komplexe Aufgabe, die den Rahmen hier sicher sprengt.

    Aber wir haben dafür eine gute Lösung: Installiere dir Mumble (zypper in mumble) und verbinde dich mit http://www.interhacktive.de. [rant on]Diese Vollidioten Forensoftware wandelt jeden URL in einen HTTP- Link um.

    Du verbindest dich mit Mumble nur auf den Host: www . interhacktive . de (ohne Leerzeichen). Dieser PHP- Müll wird von Version zu Version unbrauchbarer und die bedingt versierten Admins hier kriegen nicht mal vernünftige Inline-Code-Tags hin.[rant off]


    Das open source Mumble ist das wesentlich bessere Teamspeak. Du brauchst also irgendein funkionierendes Micro und funktionierende Soundausgabe.

    Dann können wir das zusammen in einer Screen- Session entwickeln.

    (screen ist ein Terminalmultiplexer; wir tippen und lesen also gleichzeitig in einer echten Konsole, nachdem du dich mit SSH auf einem unserer Rechner eingeloggt hast)

    Wir reden also darüber, während ich sehe, was du tippst, und du siehst, was ich tippe.

    Effektiver kann man nicht lernen.

    Ok. Du lauscht meinem endlosen Sermon...

    Umsonst is nix.

  • Berichtigung


    Sehr gerne und mit Dank.


    Bei der Verbindung mit interhacktive kommt die Meldung, daß das Zertifikat abgelaufen ist.

    Die Zertifikate sind bis 2019 und 2020 gültig.

    Ich bin da nicht firm und habe dergleichen sehr selten benutzt, deswegen a priori erst mal Sicherheitsbedenken.


    Warte also erst mal auf Ihren Rat diesbezüglich.

    Dell Latitude 7470, 4 x i7 6600U, 32 GB, 1TB NVMe

    Tumbleweed, KDE Plasma

    Für den Inhalt des Beitrages 280750 haftet ausdrücklich der jeweilige Autor: baumkraxler

  • Das habe ich gerade bereinigt.

    Dieses Zert wird lediglich für die TLS (TransportLevelSecurity aka. SSL) Verschlüsselung verwendet.

    Die stammen alle von Letsencrypt und sind knapp ein halbes Jahr gültig.

    Eigentlich hätte das vollautomatisch und völlig transparent erneuert werden. Es wurde auch erneuert, aber dem Mumble- Server war das scheinbar diesmal egal - trotz korrektem Hook-Script.


    Es ist vom Sicherheitsaspekt auch ziemlich egal: Die Verschlüsselung funktioniert trotzdem auf die gleiche sichere/unsichere Weise - egal ob abgelaufen, oder nicht. Man begrenzt die Lebenszeit dieser Zertifikate, um ein klein wenig dem Gehacktwerden vorzubeugen.


    Wie auch immer: Jetzt ist das Zert wieder gültig.