Ponowne formatowanie dużej liczby plików XML


11

Manipuluję dużą liczbą plików XML rozproszonych w zagnieżdżonej strukturze katalogów.

Próbowałem następujące:

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

Problem polega na tym, że generuje sformatowane dane wyjściowe XML na ekranie, ale nie zmienia pliku.

Jak mogę zmienić to polecenie, aby zmienić rzeczywistą zawartość pliku?

Odpowiedzi:


23

Można to zrobić findbezpośrednio, używając -exec:

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

To, co -execzostanie przekazane, zostanie wywołane raz na znaleziony plik, a parametry szablonu {}zostaną zastąpione bieżącą nazwą pliku. Na \;końcu polecenia find kończy linię.

W xargstym przypadku użycie naprawdę nie jest konieczne, ponieważ musimy wywoływać xmllintjeden plik, ponieważ nazwy plików wejściowych i wyjściowych muszą być określone w ramach tego samego wywołania.

xargsbyłoby potrzebne, gdyby polecenie, do którego przesyłane było polecenie find, działało na wielu plikach jednocześnie, a ta lista była długa. Nie możesz tego zrobić w tym przypadku, ponieważ musisz przekazać pojedynczą nazwę pliku do --outputopcji xmllint. Bez tego xargsmoże wystąpić błąd „Zbyt długa lista argumentów”, jeśli przetwarzasz wiele plików. xargsobsługuje również ciągi zamiany plików z -Iopcją:

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

Zrobi to samo co find -execpowyższe polecenie. Jeśli któryś z folderów ma nieparzyste znaki w podobnych przestrzeniach, musisz użyć -0opcji findi xargs. Ale używanie xargsz -Iimplikuje opcję, -L 1która oznacza, że ​​i tak przetwarzasz tylko 1 plik na raz, więc równie dobrze możesz użyć bezpośrednio findz -exec.


@manatwork dzięki za zmiany - lepkie palce; o)
didster

Właśnie to uruchomiłem i wydaje się, że to działa! Wielkie dzięki za szybką i zwięzłą odpowiedź!
Harry,

2
„To się nie powiedzie, jeśli lista plików jest zbyt duża”: Nie, nie zawiedzie (przetwarza pojedynczy plik naraz), a w rzeczywistości find … -execjest to najbardziej bezpośredni sposób na zrobienie tego.
Gilles 'SO - przestań być zły'

@Gilles Dobra uwaga! Zaktualizowałem odpowiednio swoją odpowiedź.
didster

1
Działa to ze względu na to, że xmllintnajpierw ładuje pełny dokument xml do pamięci, a dopiero potem parsuje / wypisuje. Pozwala to na przetwarzanie dokumentów w miejscu.
gavenkoa

6

Zazwyczaj atakuję te problemy warstwą pośrednią. Napisz skrypt powłoki, który robi to, co chcesz i nazwij to. Proponuję na początek

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

Wypróbuj go ręcznie na pliku lub dwóch, a następnie możesz go zastąpić w xargs

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

To wygląda na dobre podejście, gdybym musiał w przyszłości dokonywać bardziej złożonych manipulacji. Dzięki za odpowiedzi.
Harry,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.