Riformattazione di un gran numero di file XML


11

Sto manipolando un gran numero di file XML sparsi in una struttura di directory nidificata.

Ho provato quanto segue:

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

Il problema è che genera sullo schermo l'output XML formattato, ma non modifica il file.

Come posso modificare questo comando in modo che il contenuto del file effettivo venga modificato?

Risposte:


23

Questo può essere fatto finddirettamente usando -exec:

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

Ciò che viene passato -execverrà richiamato una volta per file trovato con i parametri del modello {}sostituiti con il nome del file corrente. Il \;alla fine del comando find termina la riga.

L'uso di xargsnon è davvero necessario in questo caso perché dobbiamo invocare xmllintuna volta per file poiché sia ​​i nomi dei file di input che quelli di output devono essere specificati nella stessa chiamata.

xargssarebbe necessario se il comando da cui veniva reindirizzato da find funzionava su più file alla volta e tale elenco era lungo. Non puoi farlo in questo caso, poiché devi passare il singolo nome file --outputall'opzione di xmllint. Senza di xargste potresti finire con un errore "Elenco argomenti troppo lungo" se stai elaborando molti file. xargssupporta anche le stringhe di sostituzione file con l' -Iopzione:

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

Farebbe lo stesso del find -execcomando sopra. Se una delle tue cartelle ha caratteri dispari in spazi simili, dovrai utilizzare le -0opzioni di finde xargs. Ma usare xargscon -Iimplica l'opzione -L 1che significa comunque elaborare solo 1 file alla volta, quindi puoi anche usarlo direttamente findcon -exec.


@manatwork grazie per le modifiche - dita appiccicose; o)
didster

Ho appena eseguito questo e sembra funzionare a meraviglia! Mille grazie per la pronta e concisa risposta!
Harry,

2
"Questo fallirà se l'elenco dei file è troppo grande": No, non fallirà (sta elaborando un singolo file alla volta), e in effetti find … -execè il modo più diretto per farlo.
Gilles 'SO- smetti di essere malvagio'

@Gilles Buono punto! Ho aggiornato la mia risposta di conseguenza.
didster,

1
Ciò funziona a causa del fatto che xmllintprima carica il documento XML completo in memoria e solo successivamente analizza / scrive. Ciò consente l'elaborazione sul posto del documento.
gavenkoa,

6

In genere attacco questi problemi con uno strato di indiretta. Scrivi uno script di shell che fa quello che vuoi e chiamalo. Suggerirei come inizio

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

Provalo su un file o due a mano, quindi puoi sostituirlo negli xargs

find . -name "*.xml" -type f | xargs -- xmltidy.sh

Questo sembra un buon approccio se avessi bisogno di fare manipolazioni più complesse in futuro. Grazie per la risposta.
Harry,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.