Reformatage d'un grand nombre de fichiers XML

11

Je manipule un grand nombre de fichiers XML dispersés dans une structure de répertoires imbriqués.

J'ai essayé ce qui suit:

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

Le problème est que cela génère la sortie XML formatée à l'écran, mais ne modifie pas le fichier.

Comment puis-je modifier cette commande afin que le contenu réel du fichier soit modifié?

Harry
la source

Réponses:

23

Cela peut être fait finden utilisant directement -exec:

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

Ce qui est passé -execsera invoqué une fois par fichier trouvé avec les paramètres du modèle {}remplacés par le nom du fichier actuel. La \;fin de la commande find termine simplement la ligne.

L'utilisation de xargsn'est pas vraiment nécessaire dans ce cas car nous devons invoquer xmllintune fois par fichier car les noms des fichiers d'entrée et de sortie doivent être spécifiés dans le même appel.

xargsserait nécessaire si la commande redirigée depuis find fonctionnait sur plusieurs fichiers à la fois et que cette liste était longue. Vous ne pouvez pas le faire dans ce cas, car vous devez passer le nom de fichier unique à l' --outputoption de xmllint. Sans cela, xargsvous pourriez vous retrouver avec une erreur "Argument List too long" si vous traitez beaucoup de fichiers. xargsprend également en charge les chaînes de remplacement de fichier avec l' -Ioption:

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

Ferait la même chose que la find -execcommande ci-dessus. Si l'un de vos dossiers contient des caractères impairs dans des espaces similaires, vous devrez utiliser les -0options de findet xargs. Mais utiliser xargsavec -Iimplique l'option -L 1qui ne signifie de toute façon que traiter 1 fichier à la fois, vous pouvez donc aussi utiliser directement findavec -exec.

didster
la source
@manatwork merci pour les modifications - doigts collants; o)
didster
Je viens de lancer cela et cela semble fonctionner un régal! Merci beaucoup pour la réponse rapide et concise!
Harry
2
"Cela échouera si la liste des fichiers est trop volumineuse": Non, cela n'échouera pas (il traite un seul fichier à la fois), et c'est en fait find … -execle moyen le plus direct de le faire.
Gilles 'SO- arrête d'être méchant'
@Gilles Bon point! J'ai mis à jour ma réponse en conséquence.
didster
1
Cela fonctionne en raison du fait que xmllinttout d'abord charge le document xml complet dans la mémoire et ensuite seulement l'analyse / l'écriture. Cela permet le traitement des documents sur place.
gavenkoa
6

J'attaque généralement ces problèmes avec une couche d'indirection. Écrivez un script shell qui fait ce que vous voulez et appelez cela. Je suggérerais pour commencer

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

L'essayer à la main sur un fichier ou deux, puis vous pouvez le remplacer dans les xargs

find . -name "*.xml" -type f | xargs -- xmltidy.sh
julien
la source
Cela ressemble à une bonne approche si je devais avoir besoin de faire des manipulations plus complexes à l'avenir. Merci pour la réponse.
Harry