Neuformatierung einer großen Anzahl von XML-Dateien

11

Ich manipuliere eine große Anzahl von XML-Dateien, die über eine verschachtelte Verzeichnisstruktur verteilt sind.

Ich habe folgendes versucht:

$ find . -name "*.xml" -type f | xargs -- xmllint --format

Das Problem ist, dass die formatierte XML-Ausgabe auf dem Bildschirm generiert wird, die Datei jedoch nicht geändert wird.

Wie kann ich diesen Befehl ändern, damit der tatsächliche Dateiinhalt geändert wird?

Harry
quelle

Antworten:

23

Dies kann finddirekt erfolgen mit -exec:

find . -name "*.xml" -type f -exec xmllint --output '{}' --format '{}' \;

Was übergeben wird, -execwird einmal pro gefundener Datei aufgerufen, wobei die Vorlagenparameter {}durch den aktuellen Dateinamen ersetzt werden. Der \;Befehl am Ende des Suchvorgangs beendet nur die Zeile.

Die Verwendung von xargsist in diesem Fall nicht wirklich erforderlich, da wir xmllinteinmal pro Datei aufrufen müssen, da sowohl der Name der Eingabe- als auch der Ausgabedatei innerhalb desselben Aufrufs angegeben werden muss.

xargsDies wäre erforderlich, wenn der Befehl, an den von find weitergeleitet wird, mehrere Dateien gleichzeitig bearbeitet und diese Liste lang wäre. In diesem Fall können Sie dies nicht tun, da Sie den einzelnen Dateinamen an die --outputOption übergeben müssen xmllint. Ohne xargskönnten Sie den Fehler "Argumentliste zu lang" erhalten, wenn Sie viele Dateien verarbeiten. xargsunterstützt auch Zeichenfolgen zum Ersetzen von Dateien mit der -IOption:

find . -name "*.xml" -type f | xargs -I'{}' xmllint --output '{}' --format '{}'

Würde das gleiche tun wie der find -execobige Befehl. Wenn einer Ihrer Ordner ungerade Zeichen in ähnlichen Bereichen enthält, müssen Sie die -0Optionen von findund verwenden xargs. Die Verwendung xargsmit -Iimpliziert jedoch die Option -L 1, dh, es wird ohnehin nur 1 Datei gleichzeitig verarbeitet. Sie können sie also auch direkt findmit verwenden -exec.

Didster
quelle
@ Manatwork danke für die Änderungen - klebrige Finger; o)
Didster
Ich habe das gerade ausgeführt und es scheint ein Vergnügen zu sein! Vielen Dank für die schnelle und prägnante Antwort!
Harry
2
"Dies schlägt fehl, wenn die Dateiliste zu groß ist": Nein, es schlägt nicht fehl (es wird jeweils nur eine Datei verarbeitet), und dies ist in der Tat find … -execder direkteste Weg, dies zu tun.
Gilles 'SO - hör auf böse zu sein'
@ Gilles Guter Punkt! Ich habe meine Antwort entsprechend aktualisiert.
Didster
1
Dies funktioniert aufgrund der Tatsache, dass xmllintzuerst ein vollständiges XML-Dokument in den Speicher geladen und erst dann analysiert / ausgeschrieben wird. Dies ermöglicht die direkte Verarbeitung von Dokumenten.
Gavenkoa
6

Normalerweise greife ich diese Probleme mit einer Indirektionsebene an. Schreiben Sie ein Shell-Skript, das macht, was Sie wollen, und nennen Sie das. Ich würde als Anfang vorschlagen

#! /bin/sh
for file
do
   xmllint --format $file > $file.tmp && mv $file.tmp $file
done

Wenn Sie es an einer oder zwei Dateien von Hand ausprobieren, können Sie es in den xargs ersetzen

find . -name "*.xml" -type f | xargs -- xmltidy.sh
julianisch
quelle
Dies scheint ein guter Ansatz zu sein, wenn ich in Zukunft komplexere Manipulationen durchführen muss. Danke für die Antwort.
Harry