Переформатирование большого количества файлов XML


11

Я манипулирую большим количеством XML-файлов, разбросанных по всей структуре вложенных каталогов.

Я попробовал следующее:

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

Проблема в том, что генерирует форматированный XML-вывод на экране, но не меняет файл.

Как я могу изменить эту команду, чтобы фактическое содержимое файла изменилось?

Ответы:


23

Это может быть сделано с findпомощью -exec:

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

То, что передано, -execбудет вызываться один раз для каждого найденного файла с {}заменой параметров шаблона на текущее имя файла. Команда \;on в конце команды find просто завершает строку.

В xargsэтом случае использование на самом деле не обязательно, потому что нам нужно вызывать xmllintодин раз для каждого файла, так как имена входных и выходных файлов должны быть указаны в одном вызове.

xargsбыло бы необходимо, если бы команда, передаваемая из find, работала с несколькими файлами одновременно, и этот список был длинным. Вы не можете сделать это в этом случае, так как вам нужно передать одно имя файла --outputопции xmllint. Без этого xargsвы можете получить ошибку «Список аргументов слишком длинный», если вы обрабатываете много файлов. xargsтакже поддерживает строки замены файлов с -Iопцией:

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

Сделал бы так же, как find -execкоманда выше. Если в любой из ваших папок есть одинаковые символы в одинаковых пробелах, вам нужно будет использовать -0опции findи xargs. Но использование xargsс -Iподразумевает опцию, -L 1которая означает, что обрабатывать только 1 файл за раз, так что вы также можете напрямую использовать findс -exec.


@manatwork спасибо за правки - липкие пальцы; o)
Дидстер

Я только что запустил это, и это, кажется, работает удовольствие! Большое спасибо за быстрый и краткий ответ!
Гарри

2
«Это не удастся, если список файлов слишком велик». Нет, не удастся (он обрабатывает один файл за раз), и на самом деле find … -execэто самый прямой способ сделать это.
Жиль "ТАК - перестать быть злым"

@ Жиль Хорошая мысль! Я обновил свой ответ соответственно.
Дидстер

1
Это работает из-за того, что xmllintсначала загружается полный XML-документ в память, а затем разбирается / записывается. Это позволяет обрабатывать документ на месте.
gavenkoa

6

Я обычно нападаю на эти проблемы со слоем косвенности. Напишите сценарий оболочки, который делает то, что вы хотите, и назовите это. Я бы предложил для начала

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

Попробуйте его на файл или два вручную, затем вы можете заменить его в xargs

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

Это похоже на хороший подход, если мне нужно будет делать более сложные манипуляции в будущем. Спасибо за ответ.
Гарри
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.