Verwenden von awk zum Ersetzen von Text zwischen zwei Zeichenfolgen oder Mustern

Lesezeit: 11 Minuten

Benutzer-Avatar
d.ariel

Ich hatte hier eine laufende Frage, aber ich bin neu bei Stack und irgendwie wurde der Thread gesperrt oder entfernt: Thread

Ich arbeite mit einer WordPress-Datenbank mit etwa 60.000 „Posts“ in der Spalte „post_content“, die ich entfernen möchte <p> HTML-Tags und den Text dazwischen. . Mein Beitragsinhalt sieht so aus:

<p style="text-align: left;"><span style="color: #fffff;">
An entire paragraph of text around 200 words
</span></p>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>

Das p Tags werden identisch sein und nur einmal pro Beitrag vorkommen, mit Ausnahme der Farbe, die bei einigen Beiträgen möglicherweise anders sein kann.

Die erwartete Ausgabe sollte wie folgt aussehen:

[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>

Ich möchte den gesamten Text in den Absatz-Tags entfernen. Was ich also entfernen möchte, ist der Text “Ein ganzer Textabschnitt mit etwa 200 Wörtern”. Dieser Text ist in jedem einzelnen Beitrag anders, aber die eine Konstante ist die <p> Tag öffnen und schließen.

Aus meiner letzten Frage dieser Befehl: By user “PS”.

awk '/<p/,/<\/p>/{next} {print $0}' inputfile

Wurde auf der .sql-Datenbank ausgeführt, nachdem ich sie abgelegt hatte. Aber der Text war nach einem Blick in die Datenbank immer noch vorhanden.

Jede Hilfe wäre sehr willkommen.

Update: Diese Frage wurde gelöst von: Ed Morton

Using GNU awk for multi-char RS this:
awk -v RS='</p>\\s*' -v ORS= '{sub(/<p.*/,"")} 1' file

  • Vielleicht wäre es einfacher, eine Skriptsprache mit HTML-Parsing-Bibliotheken zu verwenden.

    – bli

    30. Oktober 2016 um 7:19 Uhr

  • Das awk scheint mit den von Ihnen bereitgestellten Daten zu funktionieren. Sie erkennen, dass es sich nicht um einen Infile-Bearbeitungsbefehl handelt, sondern die verarbeitete Datei an stdout ausgibt und Sie diese in einer Datei speichern müssen?

    – James Brown

    30. Oktober 2016 um 11:28 Uhr

  • @JamesBrown Update: Habe ein wenig recherchiert und herausgefunden, wie man die Ausgabe wieder in eine SQL-Datei ausgibt. Also habe ich diesen Befehl ausgeführt: awk '/<p/,/<\/p>/{next} {print $0}' test.sql > test_awk.sql Das Problem ist, als ich dies tat, gab es keine Posts mehr in der Datenbank. Alle Beiträge wurden gelöscht. In der Tabelle “wp_posts” und alles wurde aus “wp_options” gelöscht sieht so aus, nachdem Sie diesen awk-Befehl ausgeführt haben

    – d.ariel

    30. Oktober 2016 um 14:55 Uhr


  • perl -pe 's/<p>.+?<\/p>//g' < test.sql > test_perl.sql

    – Michael – sqlbot

    30. Oktober 2016 um 15:16 Uhr

  • @Michael-sqlbot Ich habe diesen Befehl ausgeführt und natürlich Dateinamen genau ausgetauscht. Importierte die SQL-Datei und schaute auf den post_content und ich sehe, dass der Text noch vorhanden war. Es scheint weder den Text entfernt noch die HTML-Tags geändert zu haben. Ich bin mir nicht sicher, was falsch ist, aber ich dachte sicher, dass ich mit Ihrem Vorschlag bessere Ergebnisse erzielen würde. Irgendwelche Ideen?

    – d.ariel

    30. Oktober 2016 um 15:28 Uhr

Benutzer-Avatar
Ed Morton

Verwenden von GNU awk für Multi-Char-RS:

awk -v RS='</p>\\s*' -v ORS= '{sub(/<p.*/,"")} 1' file

funktioniert, ob es nur 1 oder mehrere gibt <p...</p> Paare in der Datei, zB:

$ cat file
<p style="text-align: left;"><span style="color: #fffff;">
First entire paragraph of text around 200 words
</span></p>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
<p style="text-align: left;"><span style="color: #fffff;">
Second entire paragraph of text around 200 words
</span></p>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>

.

$ awk -v RS='</p>\\s*' -v ORS= '{sub(/<p.*/,"")} 1' file
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>

Das Obige ist offensichtlich zerbrechlich und kann beispielsweise fehlschlagen <p darin erscheinen kann [Text_between_brackets]. Je mehr von <p... Zeile können Sie in der angeben sub() desto weniger zerbrechlich wird es sein, z. B. vielleicht können / sollten Sie etwas mehr wie folgt tun:

awk -v RS='</p>\\s*' -v ORS= '{sub(/<p style="text-align: left;"><span style="color: /,"")} 1' file

  • Ich habe die aktuelle Datenbank gelöscht, die funktioniert. Ich renne: awk -v RS='</p>\\s*' -v ORS= '{sub(/<p.*/,"")} 1' db_dump.sql > db_dump_awk.sql Ich erhalte diesen Fehler, wenn ich versuche, die SQL-Datei erneut in eine neue leere Datenbank zu importieren: ERROR 1136 (21S01) at line 328: Column count doesn't match value count at row 1 Ich habe es auch mit dem bearbeiteten Code versucht und dieser entfernt weder das Tag noch den Text.

    – d.ariel

    30. Oktober 2016 um 17:07 Uhr


  • Außerdem habe ich gerade versucht, die Datenbank zu sichern und die gesicherte .sql-Datei erneut in eine neu erstellte Datenbank zu importieren, und der Fehler wird nicht ausgelöst, solange ich den awk-Befehl nicht für die Datei ausführe.

    – d.ariel

    30. Oktober 2016 um 17:13 Uhr

  • Druckt das von mir gepostete Skript die erwartete Ausgabe angesichts Ihrer geposteten Beispieleingabe? Wenn nein, inwiefern ist es anders? Wenn es genau das tut, was Sie für Ihre Beispieleingabe wünschen, aber für Ihre echte Eingabe fehlschlägt, repräsentiert Ihre Beispieleingabe nicht wirklich Ihre echte Eingabe, und Sie müssen ein wirklich repräsentativeres Beispiel finden und veröffentlichen. Wenn es bei Ihrer Beispieleingabe nicht funktioniert, verwenden Sie vielleicht nicht GNU awk oder Ihre Eingabe ist nicht die gleiche wie die, die Sie gepostet haben, teilen Sie uns die Symptome des Fehlers/Unterschieds mit, wenn Sie Hilfe beim Debuggen benötigen.

    – Ed Morton

    30. Oktober 2016 um 17:32 Uhr


  • Grundsätzlich führe ich den Befehl im Terminal aus und er wird beendet, ohne etwas zu drucken oder einen Fehler zu verursachen. Ich gehe davon aus, dass der Befehl erfolgreich ausgeführt wurde. Ich bin mir nicht sicher, ob ich GNU awk separat installieren muss oder nicht. Nach einigem Debuggen auf meiner Seite sehe ich, dass der Zieltext in der realen Eingabe in der .sql-Datei entfernt wird, aber beim Versuch, diese .sql-Datei in eine neue Datenbank zu importieren, eine Fehlermeldung zurückbleibt.

    – d.ariel

    30. Oktober 2016 um 18:05 Uhr

  • Die gute Nachricht ist, dass ich es dank Ihnen zum Laufen gebracht habe. Ich habe eine etwas ältere Kopie derselben Datenbank abgelegt, die etwas weniger mit phpmyadmin-Suche und -Ersetzung missbraucht wurde, und aus irgendeinem Grund funktionierte sie. Nicht sehr wissenschaftlich, aber die Regex und der Befehl, die Sie in Ihre Antwort eingefügt haben, funktionierten tatsächlich voll funktionsfähig. Vielen Dank

    – d.ariel

    30. Oktober 2016 um 18:35 Uhr

Sie können den folgenden sed-Befehl versuchen –

sed '/<p/,/<\/p/d' kk.txt

Verwenden Sie das Escape-Zeichen für </p.

  • Hey, danke für deine Antwort. Ich habe den Befehl an einer Kopie der database.sql ausprobiert, dann die Datenbank in mysql importiert und über phpmyadmin überprüft. Es zeigte immer noch den Absatztext. Als ich den genauen Befehl ausführte, den Sie gepostet hatten, sah es so aus, als würde er suchen und ersetzen, aber als ich ihn überprüfte, wie ich sagte, war der Text noch vorhanden. <p style="text-align: left;"><span style="color: #2c8ebf;"> This text was still present </span></p></br>

    – d.ariel

    30. Oktober 2016 um 12:39 Uhr


  • Update: OK, also habe ich den sed-Befehl so gemacht: sed -i '/<p/,/<\/p/d' test_sed.sql Das Ergebnis war nun, dass es keine Posts und viele fehlende Tabellen gab, nachdem ich den Befehl ausgeführt hatte. Ich habe die Datenbank überprüft, nachdem ich den Befehl sed verwendet und die Datenbank importiert und dann über phpmyadmin angesehen habe. Mache ich immer noch etwas falsch? Es sieht so aus, als ob der von Ihnen gesendete Code tatsächlich den Schrägstrichen entgeht.

    – d.ariel

    30. Oktober 2016 um 14:50 Uhr

  • @d.ariel ja, deine Regex ist zu “gierig”. Sie müssen übereinstimmen <p> gefolgt von einer beliebigen Anzahl von Zeichen außer </p>dann gefolgt von </p>. Andernfalls Too<p>This Thing</p>something that should not be removed<p>That thing</p> Little wird reduziert auf Too Little denn das ganze <p>...</p> wurde abgeglichen.

    – Michael – sqlbot

    30. Oktober 2016 um 15:08 Uhr

  • @Michael-sqlbot Soll ich awk oder sed verwenden? Beide Regex-Bits waren bei beiden von mir verwendeten Befehlen “gierig”. Der genaue Text lautet wie folgt: <p style="text-align: left;"><span style="color: #2c8ebf;"> Text I want removed. </span></p> Sie beginnen alle mit <p style="text-align: left:"> Könnten Sie mir zufällig eine bessere Regex geben?

    – d.ariel

    30. Oktober 2016 um 15:15 Uhr

  • @d.ariel – Können Sie einige Daten der Eingabedatei teilen, die sich auf Ihre aktuelle Datei beziehen, in der der Text noch vorhanden ist, den Sie nicht dort haben möchten.

    – VIPIN KUMAR

    30. Oktober 2016 um 17:57 Uhr

Benutzer-Avatar
Bill Karwin

Ich würde weder awk noch sed oder perl verwenden. Wie Sie festgestellt haben, ist es schwierig, die regulären Ausdrücke korrekt zu verwalten. Es gibt einen alten Witz:

Manche Leute denken, wenn sie mit einem Problem konfrontiert werden: „Ich weiß, ich werde reguläre Ausdrücke verwenden.“ Jetzt haben sie zwei Probleme. — Jamie Zawinski, 1997

Ich würde nicht einmal die Daten ausgeben und die Dump-Datei bearbeiten. Das ist auch schwierig.

Eine einfachere Lösung besteht darin, in MySQL integrierte XPath-Funktionen zu verwenden, um jeden Beitrag direkt in der Datenbank zu bearbeiten. Ich habe die folgende Lösung getestet und eine Version Ihres Beispiel-Post-Inhalts mit der abgefragt <p> -Tag (und alles darin) entfernt.

mysql> SELECT post_content, 
       UpdateXml(post_content, '/p', '') AS post_content_without_p 
       FROM posts\G

Und die Ausgabe, die den Vorher- und Nachher-Inhalt zeigt, lautet:

*************************** 1. row ***************************
          post_content: <p style="text-align: left;"><span style="color: #fffff;">
An entire paragraph of text around 200 words
</span></p>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>

post_content_without_p: 
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="309" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
[Text_between_brackets]
<iframe src="http://somewebsite.com" width="250" height="250" frameborder="0" marginwidth="0" marginheight="0" scrolling="NO"></iframe>
1 row in set (0.00 sec)

Das UpdateXml() Die Funktion ist Teil der dokumentierten integrierten Funktionen von MySQL. Es braucht drei Argumente:

  • Die zu lesende Spalte oder der zu lesende Ausdruck, der XML enthalten sollte (HTML ist eine Teilmenge von XML).
  • Der XPath-Ausdruck, welcher Teil dieses XML abgeglichen werden soll.
  • Eine Ersetzungszeichenfolge, die den abgeglichenen XML-Code ersetzen soll.

Sobald Sie zufrieden sind, dass Ihre Abfrage das tut, was Sie wollen, können Sie den Inhalt in Ihrer Tabelle aktualisieren, ohne ihn zu sichern und wiederherzustellen:

mysql> UPDATE posts SET post_content = UpdateXml(post_content, '/p', '');

Erstellen Sie immer eine Sicherungskopie, bevor Sie eine solche Änderung versuchen! Oder kopieren Sie die Daten während des Experimentierens in eine andere Datenbank.

1241850cookie-checkVerwenden von awk zum Ersetzen von Text zwischen zwei Zeichenfolgen oder Mustern

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy