Переформатування великої кількості 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буде викликано один раз для кожного знайденого файлу з {}заміненими параметрами шаблону поточним іменем файлу. Команда \;в кінці знаходження просто закінчує рядок.

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

xargsзнадобиться, якби команда, на яку перебувають з пошуку, працювала над кількома файлами одночасно, і цей список був довгим. У цьому випадку ви не можете цього зробити, оскільки вам потрібно передати одне ім'я файлу до --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)
didster

Я щойно запустив це, і, здається, працює частування! Велике спасибі за швидку та стислу відповідь!
Гаррі

2
"Це не вдасться, якщо список файлів занадто великий": Ні, він не вийде з ладу (це обробка одного файлу за один раз), і насправді find … -execце найбільш прямий спосіб зробити це.
Жил "ТАК - перестань бути злим"

@Gilles Добрий момент! Я відповідно оновив свою відповідь.
didster

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.