Wie kann ich ^ L-Code in vielen Dateien in Ubuntu ändern?

8

Ich habe viele XML-Dateien, über 50000 davon.

In einigen XML-Dateien sind einige Dateien so geschrieben

<filename>abc.JPEG<^Lilename>

^List nur ein Zeichen, aber ich kann nicht finden, was ^Lmit Google bedeutet.

Wenn ich catden Inhalt einer Datei drucke, wird Folgendes angezeigt

<filename>abc.JPEG<
                   ilename>

Wie auch immer, möchte ich ändern <filename>abc.JPEG<^Lilename>zu<filename>abc.JPEG</filename>

Ich habe bereits einen Befehl zum Ändern eines Wortes in vielen Dateien gefunden, z

find . -exec perl -pi -e 's/[find_word]/[change_word]/g' {} \;

Aber dieser Befehl funktioniert in meinem Fall nicht, weil er das Suchwort nicht erkennen kann, wenn ich nur tippe ^L.

Wie kann ich ändern , <filename>abc.JPEG<^Lilename>um <filename>abc.JPEG</filename>in vielen Dateien?

Yang
quelle
6
Anscheinend wird jemand verwendet, <\filename>anstatt </filename>in einem Kontext, in dem \fdies als Formular-Feed-Zeichen interpretiert wird. Sie sollten wahrscheinlich die Quelle dieser Dateien ausfindig machen und den Entwickler auf das Problem mit dem Generierungswerkzeug hinweisen. Zum Reparieren der Dateien ist die akzeptierte Antwort in Ordnung.
Hans-Martin Mosner

Antworten:

17

Strg-L (dargestellt als ^L) ist das Zeichen "Formularvorschub". In ASCII hat es den Dezimalwert 12 ( List der 12. Buchstabe des Alphabets) oder den Hexadezimalwert 0c:

$ printf 'foo\x0cbar\n' | cat -et
foo^Lbar$

$ printf 'foo\x0cbar\n'
foo
   bar

Sie können es mit Tools wie sed ersetzen, indem Sie den hexadezimalen Escape-Code angeben:

$ printf 'foo\x0cbar\n' | sed 's/\x0c//'
foobar

Alternativ können Sie auch ^Ldirekt mit der Tastatursequenz CTRL+ V CTRL+ komponierenL

sed 's/CTRL+VCTRL+L//'

Für Ihren spezifischen Ersatz angegeben

$ printf '<\x0cilename\n'
<
 ilename

dann

$ printf '<\x0cilename\n' | sed 's/<\x0c/<\/f/g'
</filename

(Der gModifikator wird hinzugefügt, falls mehr als eine Instanz pro Zeile vorhanden ist.)

Steeldriver
quelle
In meinem Fall funktioniert "$ printf '<\ x0cilename \ n' | sed 's / <\ x0c / <\\ f / g'" nicht. Laut Ihrer Antwort lautet jedoch "$ find. -Exec perl -pi -es / <\ x0cilename> / <\ / filename> / g '{} \;" funktioniert gut. Vielen Dank für Ihre Antwort :)
Yang
@ Yang Entschuldigung, ich habe gerade festgestellt, dass ich in meiner Antwort Schrägstrich und Schrägstrich verwechselt habe (jetzt korrigiert) - immer noch nicht sicher, warum das die sed-Version daran gehindert hätte zu funktionieren
steeldriver
Eine sehr gute Antwort! Es wäre sogar noch besser, wenn es beispielsweise eine enthält find, die diese 50000 XML-Dateien durchläuft und jede automatisch verarbeitet (und auch ein Backup erstellt).
Kingsley
2

Wie Hans-Martin Mosner in den Kommentaren ausführt, scheint es, dass jemand beim Generieren des XML Backslashes anstelle von Forward Slashes verwendet hat (oder möglicherweise den gesamten <filename>Abschnitt durch einen Unix-zu-Windows-Konverter geführt hat, der über Schrägstriche hinweg war). \fist eine selten verwendete Escape-Sequenz für ein Formular-Feed-Zeichen, auch bekannt als U + 0C oder ^ L. Ein späterer Schritt der Pipeline ersetzte dann das \fdurch wörtliche U + 0C-Zeichen.

Glücklicherweise ist U + 0C ein äußerst seltenes Zeichen, das in keiner Art von XML absichtlich vorkommt . Und da nur \fwürde dies produzieren, im Gegensatz zu (sagen wir) \goder \keine universelle Suchen und ersetzen nicht nur reparieren , </filename>sondern auch </folder>, </file>oder irgendetwas anderes , das verstümmelt wurde.

Das ist es, was das Sed-Skript von Steeldriver macht. Ich würde es nur etwas allgemeiner machen:

sed 's|\x0c|/f|g'

Dies bedeutet "(s) wap alle Instanzen von \x0c(dh U + 0C) auf /f(g) lobally".

Draconis
quelle
2

\fist das Formular-Feed-Zeichen in Perl. Es sieht so aus, als ob diese fehlerhaften Dateien von jemandem erstellt wurden, der sowohl in Perl als auch in XML neu ist.

Hier ist ein viel früherer Fix - der auch die Ziele des OP erfüllt, die Aktualisierung aller Dateien zu automatisieren, im Gegensatz zu der akzeptierten Antwort mit sed, die jeweils nur für eine Datei funktioniert, da sie nicht mit gekoppelt ist find.

\fkann einfach selbst anstelle des Hexadezimalcodes verwendet werden x0c.

find . -type f -exec perl -pi.bkp -e 's [ \f ilename ][ /f ilename ]gx' {} \;

Hier habe ich -type fzu tel hinzugefügt , findum nur einfache Dateien zurückzugeben - andernfalls findwird .in der Liste zurückgegeben und eine Warnung ausgelöst, wenn Sie versuchen, sie zu bearbeiten, obwohl alles andere weiterhin funktioniert.

Ich habe es auch einfacher gemacht, den regulären Ausdruck zu sehen, indem ich das xFlag verwendet habe, das echte Leerzeichen ignoriert, sodass Sie die Elemente Ihres regulären Ausdrucks entfernen können. Wenn Ihnen das nicht gefällt, ist es hier ohne:

find . -type f -exec perl -pi.bkp -e 's[\filename][/filename]g' {} \;

Und in dem wahrscheinlichen Fall, dass alle Formularvorschubzeichen falsch sind und alle durch ersetzt werden sollten /f, können Sie den Einzeiler noch weiter verkleinern:

find . -type f -exec perl -pi.bkp -e 's[\f][/f]g' {} \;

Sie müssen keine Schrägstriche verwenden, um die Elemente ( s///) Ihres Regex-Ersetzungsbefehls in Perl zu umgeben. Sie können ein beliebiges Symbol verwenden. Wenn Sie sich jedoch für die Verwendung eines gepaarten klammerartigen Symbols entscheiden, müssen Sie beide verwenden: s[old][new]zum Beispiel.

Da ich keine Schrägstriche verwende, muss ich keinen Schrägstrichen entkommen.

Wie für -i.bkp: perl -pi -eErmöglicht das Bearbeiten vor Ort. Wenn Sie jedoch eine zusätzliche Versicherung wünschen, falls Ihr Perl-Programm zum Suchen und Ersetzen falsch ist, können Sie eine Dateierweiterung eingeben, damit eine Kopie der Originaldateien für erstellt wird Du. Hier habe ich benutzt .bkp.

In den neuesten Perl-Versionen wurde die direkte Bearbeitung aktualisiert, um die Ausfallsicherheit zu erhöhen, falls auf Ihrem System ein ernstes Problem wie Stromausfall oder Speicherplatzmangel auftritt. Hier ist der Perl-Autor Brian D Foy über die verbesserte In-Place-Bearbeitung in den letzten Perls.

Sie sollten mit Perl für diese Art von Aufgaben betrachten, weil es eine extrem leistungsstarke und dennoch unterbewertet Allzweck- Programmiersprache ist, von deren ursprünglichen Entwurfsziele war zu ersetzen sedund awkmit etwas viel besser.

Perl 5 regex Matching - Fähigkeiten und verbesserte regex Syntax weit über die von sed, awkund in der Tat jeder anderen Programmiersprache abgesehen von Perl 6, so dass Perl die vernünftigste Wahl für einfache und erweitern Regex Manipulationen.

Zur Verdeutlichung: Funktioniert auch sedmit OK findund Sie können auch sed -i.bkpeine Sicherungskopie jeder bearbeiteten Datei erstellen, aber soweit ich weiß, bietet sie nicht die zusätzliche Ausfallsicherheit in Perl 5.28 und höher. Es verwendet auch die klobigere und weitaus weniger leistungsfähige traditionelle UNIX ® -Regex-Syntax.

Medlock Perlman
quelle