Это на самом деле просто объяснение ответа Юзема , но я не чувствовал, что так много нужно редактировать кому-то другому, а комментарии не позволяют форматировать, так что ...
rdom (){local IFS=\> ; read -d \< E C ;}
Давайте назовем это «read_dom» вместо «rdom», выделим его немного и используем более длинные переменные:
Итак, он определяет функцию с именем read_dom. Первая строка делает IFS (разделитель поля ввода) локальным для этой функции и изменяет его на>. Это означает, что когда вы читаете данные вместо того, чтобы автоматически разделяться на пробелы, символы табуляции или перевода строки, они разделяются на «>». В следующей строке написано, что нужно читать ввод из stdin, и вместо того, чтобы останавливаться на новой строке, останавливаться, когда вы видите символ «<» (флаг -d для deliminator). То, что читается, затем разделяется с помощью IFS и присваивается переменной ENTITY и CONTENT. Итак, возьмите следующее:
<tag>value</tag>
Первый вызов, чтобы read_domполучить пустую строку (так как «<» является первым символом). Это делится IFS на просто '', так как нет символа '>'. Read затем назначает пустую строку обеим переменным. Второй вызов получает строку «тег> значение». Затем IFS разделяется на два поля: «тег» и «значение». Read затем присваивает переменные, такие как: ENTITY=tagи CONTENT=value. Третий вызов получает строку '/ tag>'. Это разделено IFS на два поля '/ tag' и ''. Read затем присваивает переменные, такие как: ENTITY=/tagи CONTENT=. Четвертый вызов вернет ненулевой статус, потому что мы достигли конца файла.
Теперь его цикл while немного очищен, чтобы соответствовать приведенному выше:
while read_dom;doif[[ $ENTITY ="title"]];then
echo $CONTENT
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
В первой строке просто сказано: «пока функция read_dom возвращает нулевой статус, сделайте следующее». Вторая строка проверяет, является ли объект, который мы только что видели, «заголовком». Следующая строка повторяет содержание тега. Четыре линии выходов. Если это не заголовок, цикл повторяется в шестой строке. Мы перенаправляем «xhtmlfile.xhtml» в стандартный ввод (для read_domфункции) и перенаправляем стандартный вывод в «titleOfXHTMLPage.txt» (эхо из более раннего в цикле).
Теперь с учетом следующего (аналогично тому, что вы получаете, перечисляя ведро на S3) для input.xml:
$ cat example.xml |./bash_xml.sh
bar type is: metal
foo size is:1789
EDIT 3 другой пользователь сказал, что у него проблемы с ним во FreeBSD, и предложил сохранить состояние выхода из чтения и вернуть его в конце read_dom, например:
Если вы сделаете IFS (разделитель входных полей) глобальным, вы должны в конце сбросить его на исходное значение, я отредактировал ответ, чтобы получить его. В противном случае любое другое разбиение ввода, которое вы сделаете позже в вашем скрипте, будет испорчено. Я подозреваю, что local не работает для вас, потому что вы используете bash в режиме совместимости (например, ваш shbang #! / Bin / sh) или это древняя версия bash.
Чад
30
То, что вы можете написать свой собственный парсер, не означает, что вы должны это делать.
Стивен Недзельски
1
@chad это , безусловно , говорит о AWS»рабочего процесса / реализации , что я искал ответ на„Баш XML“также WGET содержимого ведра S3!
Аластер
2
@Alastair см github.com/chad3814/s3scripts для набора Баш сценариев , которые мы используем , чтобы манипулировать объектами S3
чадь
5
Назначение IFS в локальной переменной хрупко и не обязательно. Просто сделайте:, IFS=\< read ...который будет устанавливать IFS только для вызова чтения. (Обратите внимание, что я никоим образом не одобряю практику использования readдля анализа xml, и я считаю, что это чревато опасностью и этого следует избегать.)
Уильям Перселл,
64
Вы можете сделать это очень легко, используя только bash. Вам нужно только добавить эту функцию:
rdom (){local IFS=\> ; read -d \< E C ;}
Теперь вы можете использовать rdom как read, но для html документов. При вызове rdom назначит элемент переменной E, а содержимое - переменной C.
Например, чтобы сделать то, что вы хотели сделать:
while rdom;doif[[ $E = title ]];then
echo $C
exitfidone< xhtmlfile.xhtml > titleOfXHTMLPage.txt
не могли бы вы уточнить это? Могу поспорить, что это совершенно ясно для вас ... и это могло бы быть отличным ответом - если бы я мог рассказать, что вы там делали ... вы можете немного разбить его, возможно, генерируя какой-нибудь пример выходных данных?
Алекс Грей
1
Cred to original - этот однострочный, чертовски элегантный и удивительный.
Индивидуалист
1
отличный хак, но мне пришлось использовать двойные кавычки, такие как echo "$ C", чтобы предотвратить расширение оболочки и правильную интерпретацию конечных строк (зависит от конца)
user311174
8
С парсингом XML с помощью grep и awk не все в порядке . Это может быть приемлемым компромиссом, если XML-файлы достаточно просты и у вас не так много времени, но это никогда нельзя назвать хорошим решением.
Петер - Восстановить Монику
59
Инструменты командной строки, которые можно вызывать из сценариев оболочки, включают в себя:
xpath - оболочка командной строки для библиотеки XPath в Perl
Xidel - работает как с URL, так и с файлами. Также работает с JSON
Я также использую xmllint и xsltproc с небольшими сценариями XSL-преобразования для выполнения обработки XML из командной строки или в сценариях оболочки.
да, второй голос / запрос - где скачать эти инструменты, или вы имеете в виду, что нужно вручную написать обертку? Я бы предпочел не тратить время на это, если в этом нет необходимости.
Дэвид
4
sudo apt-get install libxml-xpath-perl
Эндрю Вагнер,
22
Вы можете использовать утилиту xpath. Он устанавливается вместе с пакетом Perl XML-XPath.
Использование:
/usr/bin/xpath [filename] query
или XMLStarlet . Чтобы установить его на opensuse используйте:
Использование xml starlet определенно является лучшим вариантом, чем написание собственного сериализатора (как предлагается в других ответах).
Бруно фон Париж,
Во многих системах xpathпредустановленная версия не подходит для использования в качестве компонента в сценариях. См., Например, stackoverflow.com/questions/15461737/… для уточнения.
Исходя из ответа Чада, вот ПОЛНОЕ рабочее решение для анализа UML, с более точной обработкой комментариев, всего с двумя небольшими функциями (более 2-х, но вы можете смешать их все). Я не говорю, что chad's один не работал вообще, но у него было слишком много проблем с плохо отформатированными XML-файлами: так что вам нужно быть немного хитрее, чтобы обрабатывать комментарии и неуместные пробелы / CR / TAB / и т.д.
Цель этого ответа - предоставить готовые 2-функциональные функции bash для всех, кому требуется анализ UML без сложных инструментов, использующих Perl, Python или что-либо еще. Что касается меня, я не могу установить ни cpan, ни perl-модули для старой производственной ОС, над которой я работаю, и python недоступен.
Во-первых, определение слов UML, используемых в этом посте:
о, и вам понадобятся некоторые аккуратные динамические переменные для раскрашивания, которые сначала будут определены, а также экспортированы:
set-a
TERM=xterm-256colorcase ${UNAME}in
AIX|SunOS)
M=$(${print}'\033[1;35m')
m=$(${print}'\033[0;35m')END=$(${print}'\033[0m');;*)
m=$(tput setaf 5)
M=$(tput setaf 13)# END=$(tput sgr0) # issue on Linux: it can produces ^[(B instead of ^[[0m, more likely when using screenrcEND=$(${print}'\033[0m');;esac# 24 shades of grey:for i in $(seq 023);doeval g$i="$(${print} \"\\033\[38\;5\;$((232 + i))m\")";done# another way of having an array of 5 shades of grey:
declare -a colorNums=(238240243248254)for num in01234;do nn[$num]=$(${print}"\033[38;5;${colorNums[$num]}m"); NN[$num]=$(${print}"\033[48;5;${colorNums[$num]}m");done# piped decolorization:
DECOLORIZE='eval sed "s,${END}\[[0-9;]*[m|K],,g"'
Как загрузить все эти вещи:
Либо вы знаете, как создавать функции и загружать их через FPATH (ksh), либо эмулировать FPATH (bash)
Если нет, просто скопируйте / вставьте все в командной строке.
Как это работает:
xml_read [-cdlp][-x command <-a attribute>]<file.xml>[tag |"any"][attributes ..|"content"]-c = NOCOLOR
-d =Debug-l = LIGHT (no \"attribute=\" printed)-p = FORCE PRINT (whenno attributes given)-x = apply a command on an attribute andprint the result instead of the former value,in green color
(no attribute given will load their values into your shell as $ATTRIBUTE=value;use'-p' to print them as well)
xml_read server.xml title content # print content between <title></title>
xml_read server.xml Connector port # print all port values from Connector tags
xml_read server.xml any port # print all port values from any tags
В режиме отладки (-d) комментарии и проанализированные атрибуты печатаются в stderr
извините, хмарбаисе, это функции оболочки bash. Если вы хотите адаптировать их как сценарии оболочки, вам, безусловно, следует ожидать некоторых незначительных изменений! Также обновленные функции обрабатывают ваши ошибки;)
scavenger
4
Я не знаю ни одного чистого инструмента синтаксического анализа XML оболочки. Поэтому вам, скорее всего, понадобится инструмент, написанный на другом языке.
Мой модуль Perl XML :: Twig поставляется с таким инструментом:, xml_grepгде вы, вероятно, напишите, что вы хотите xml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt( -tопция дает вам результат в виде текста вместо xml)
После некоторых исследований по переводу между форматами Linux и Windows путей к файлам в XML-файлах я нашел интересные учебные пособия и решения по следующим вопросам:
Хотя существует довольно много готовых консольных утилит, которые могут делать то, что вы хотите, вероятно, потребуется меньше времени, чтобы написать пару строк кода на языке программирования общего назначения, таком как Python, который вы легко можете расширить и адаптировать к твои нужды.
Вот скрипт Python, который используется lxmlдля анализа - он принимает имя файла или URL-адрес в качестве первого параметра, выражение XPath в качестве второго параметра и печатает строки / узлы, соответствующие данному выражению.
Пример 1
#!/usr/bin/env pythonimport sys
from lxml import etree
tree = etree.parse(sys.argv[1])
xpath_expression = sys.argv[2]# a hack allowing to access the# default namespace (if defined) via the 'p:' prefix # E.g. given a default namespaces such as 'xmlns="http://maven.apache.org/POM/4.0.0"'# an XPath of '//p:module' will return all the 'module' nodes
ns = tree.getroot().nsmap
if ns.keys()andNonein ns:
ns['p']= ns.pop(None)# end of hack for e in tree.xpath(xpath_expression, namespaces=ns):if isinstance(e, str):print(e)else:print(e.text and e.text.strip()or etree.tostring(e, pretty_print=True))
lxmlможет быть установлен с pip install lxml. На Ubuntu вы можете использовать sudo apt install python-lxml.
использование
python xpath.py myfile.xml "//mynode"
lxml также принимает URL в качестве входных данных:
Примечание . Если ваш XML-файл имеет пространство имен по умолчанию без префикса (например xmlns=http://abc...), то вы должны использовать pпрефикс (предоставленный «hack») в своих выражениях, например, //p:moduleчтобы получить модули из pom.xmlфайла. В случае, если pпрефикс уже сопоставлен в вашем XML, вам нужно изменить скрипт, чтобы использовать другой префикс.
Пример 2
Одноразовый скрипт, который служит узкой цели извлечения имен модулей из файла apache maven. Обратите внимание, как перед именем узла ( module) используется пространство имен по умолчанию {http://maven.apache.org/POM/4.0.0}:
Это замечательно, когда вы либо хотите избежать установки дополнительных пакетов, либо не имеете доступа к ним. На строительной машине, я могу оправдать дополнительный за pip installкадром apt-getили yumвызова. Спасибо!
Э. Моффат
0
Метод Yuzem может быть улучшен путем инвертирования порядка <и >знаков в rdomфункции и переменных задания, так что:
rdom (){local IFS=\> ; read -d \< E C ;}
будет выглядеть так:
rdom (){local IFS=\< ; read -d \> C E ;}
Если синтаксический анализ выполняется не так, последний тег в файле XML никогда не будет достигнут. Это может быть проблематично, если вы собираетесь вывести другой файл XML в конце whileцикла.
Хотя кажется, что «никогда не анализировать XML, JSON ... из bash без надлежащего инструмента» - это хороший совет, я не согласен. Если это вспомогательная работа, то нужно искать подходящий инструмент, а затем изучать его ... Awk может сделать это за считанные минуты. Мои программы должны работать со всеми вышеупомянутыми и другими видами данных. Черт, я не хочу тестировать 30 инструментов для анализа 5-7-10 различных форматов, которые мне нужны, если я смогу решить проблему за считанные минуты. Мне плевать на XML, JSON или что-то еще! Мне нужно одно решение для всех из них.
Как пример: моя программа SmartHome работает в наших домах. Делая это, он читает множество данных в слишком многих различных форматах, которые я не могу контролировать. Я никогда не использую выделенные, надлежащие инструменты, так как я не хочу тратить больше времени на чтение нужных мне данных. С настройками FS и RS это awk-решение отлично работает для любого текстового формата. Но это может быть неправильным ответом, если ваша основная задача - работать в основном с данными в этом формате!
С проблемой парсинга XML из bash я столкнулся вчера. Вот как я делаю это для любого иерархического формата данных. В качестве бонуса - я назначаю данные непосредственно переменным в скрипте bash.
Чтобы облегчить чтение, я буду представлять решение поэтапно. Из данных теста OP я создал файл: test.xml
Разбор XML в bash и извлечение данных в 90 символов:
Мне все равно, как называется формат. Я ищу только самое простое решение. В этом конкретном случае я могу видеть из данных, что символ новой строки - это разделитель записей (RS) и поля разделителя <> (FS). В моем исходном случае у меня было сложное индексирование 6 значений в двух записях, связывая их, находя, когда данные существуют, плюс поля (записи) могут или не могут существовать. Потребовалось 4 строки awk, чтобы полностью решить проблему. Итак, адаптируйте идею к каждой потребности, прежде чем использовать ее!
Вторая часть просто смотрит на наличие искомой строки в строке (RS) и, если так, распечатывает необходимые поля (FS). Вышеуказанное заняло у меня около 30 секунд, чтобы скопировать и адаптировать последнюю команду, которую я использовал таким образом (в 4 раза дольше). И это все! Сделано за 90 символов.
Но мне всегда нужно аккуратно помещать данные в переменные в моем скрипте. Сначала я проверяю конструкции так:
В некоторых случаях я использую printf вместо print. Когда я вижу, что все выглядит хорошо, я просто заканчиваю присваивать значения переменным. Я знаю, многие думают, что «eval» - это «зло», не нужно комментировать :) Трюк отлично работает на всех четырех моих сетях в течение многих лет. Но продолжайте учиться, если вы не понимаете, почему это может быть плохой практикой! Моему решению, включая назначения переменных bash и достаточный интервал, для выполнения всех задач требуется 120 символов.
Ответы:
Это на самом деле просто объяснение ответа Юзема , но я не чувствовал, что так много нужно редактировать кому-то другому, а комментарии не позволяют форматировать, так что ...
Давайте назовем это «read_dom» вместо «rdom», выделим его немного и используем более длинные переменные:
Итак, он определяет функцию с именем read_dom. Первая строка делает IFS (разделитель поля ввода) локальным для этой функции и изменяет его на>. Это означает, что когда вы читаете данные вместо того, чтобы автоматически разделяться на пробелы, символы табуляции или перевода строки, они разделяются на «>». В следующей строке написано, что нужно читать ввод из stdin, и вместо того, чтобы останавливаться на новой строке, останавливаться, когда вы видите символ «<» (флаг -d для deliminator). То, что читается, затем разделяется с помощью IFS и присваивается переменной ENTITY и CONTENT. Итак, возьмите следующее:
Первый вызов, чтобы
read_dom
получить пустую строку (так как «<» является первым символом). Это делится IFS на просто '', так как нет символа '>'. Read затем назначает пустую строку обеим переменным. Второй вызов получает строку «тег> значение». Затем IFS разделяется на два поля: «тег» и «значение». Read затем присваивает переменные, такие как:ENTITY=tag
иCONTENT=value
. Третий вызов получает строку '/ tag>'. Это разделено IFS на два поля '/ tag' и ''. Read затем присваивает переменные, такие как:ENTITY=/tag
иCONTENT=
. Четвертый вызов вернет ненулевой статус, потому что мы достигли конца файла.Теперь его цикл while немного очищен, чтобы соответствовать приведенному выше:
В первой строке просто сказано: «пока функция read_dom возвращает нулевой статус, сделайте следующее». Вторая строка проверяет, является ли объект, который мы только что видели, «заголовком». Следующая строка повторяет содержание тега. Четыре линии выходов. Если это не заголовок, цикл повторяется в шестой строке. Мы перенаправляем «xhtmlfile.xhtml» в стандартный ввод (для
read_dom
функции) и перенаправляем стандартный вывод в «titleOfXHTMLPage.txt» (эхо из более раннего в цикле).Теперь с учетом следующего (аналогично тому, что вы получаете, перечисляя ведро на S3) для
input.xml
:и следующий цикл:
Вы должны получить:
Так что, если мы написали
while
цикл, как у Юзема:Мы получили бы список всех файлов в корзине S3.
РЕДАКТИРОВАТЬ Если по какой-то причине у
local IFS=\>
вас не работает, и вы установили его глобально, вы должны сбросить его в конце функции, как:В противном случае любое разбиение строки, которое вы сделаете позже в скрипте, будет испорчено.
РЕДАКТИРОВАТЬ 2 Чтобы разделить пары имя / значение атрибута, вы можете увеличить
read_dom()
так:Затем напишите свою функцию для анализа и получите данные, которые вы хотите, вот так:
Тогда пока вы
read_dom
звонитеparse_dom
:Затем приведен следующий пример разметки:
Вы должны получить этот вывод:
EDIT 3 другой пользователь сказал, что у него проблемы с ним во FreeBSD, и предложил сохранить состояние выхода из чтения и вернуть его в конце read_dom, например:
Я не вижу причин, почему это не должно работать
источник
IFS=\< read ...
который будет устанавливать IFS только для вызова чтения. (Обратите внимание, что я никоим образом не одобряю практику использованияread
для анализа xml, и я считаю, что это чревато опасностью и этого следует избегать.)Вы можете сделать это очень легко, используя только bash. Вам нужно только добавить эту функцию:
Теперь вы можете использовать rdom как read, но для html документов. При вызове rdom назначит элемент переменной E, а содержимое - переменной C.
Например, чтобы сделать то, что вы хотели сделать:
источник
Инструменты командной строки, которые можно вызывать из сценариев оболочки, включают в себя:
Я также использую xmllint и xsltproc с небольшими сценариями XSL-преобразования для выполнения обработки XML из командной строки или в сценариях оболочки.
источник
Вы можете использовать утилиту xpath. Он устанавливается вместе с пакетом Perl XML-XPath.
Использование:
или XMLStarlet . Чтобы установить его на opensuse используйте:
или попробуйте
cnf xml
на других платформах.источник
xpath
предустановленная версия не подходит для использования в качестве компонента в сценариях. См., Например, stackoverflow.com/questions/15461737/… для уточнения.apt-get install xmlstarlet
Этого достаточно ...
источник
apt-get install libxml-xpath-perl
.Проверьте XML2 с http://www.ofb.net/~egnor/xml2/, который преобразует XML в формат, ориентированный на строки.
источник
Исходя из ответа Чада, вот ПОЛНОЕ рабочее решение для анализа UML, с более точной обработкой комментариев, всего с двумя небольшими функциями (более 2-х, но вы можете смешать их все). Я не говорю, что chad's один не работал вообще, но у него было слишком много проблем с плохо отформатированными XML-файлами: так что вам нужно быть немного хитрее, чтобы обрабатывать комментарии и неуместные пробелы / CR / TAB / и т.д.
Цель этого ответа - предоставить готовые 2-функциональные функции bash для всех, кому требуется анализ UML без сложных инструментов, использующих Perl, Python или что-либо еще. Что касается меня, я не могу установить ни cpan, ни perl-модули для старой производственной ОС, над которой я работаю, и python недоступен.
Во-первых, определение слов UML, используемых в этом посте:
РЕДАКТИРОВАТЬ: обновленные функции, с ручкой:
Функции, во-первых, это xml_read_dom, который рекурсивно вызывается xml_read:
и второй:
и, наконец, функции rtrim, trim и echo2 (to stderr):
Раскраска:
о, и вам понадобятся некоторые аккуратные динамические переменные для раскрашивания, которые сначала будут определены, а также экспортированы:
Как загрузить все эти вещи:
Либо вы знаете, как создавать функции и загружать их через FPATH (ksh), либо эмулировать FPATH (bash)
Если нет, просто скопируйте / вставьте все в командной строке.
Как это работает:
В режиме отладки (-d) комментарии и проанализированные атрибуты печатаются в stderr
источник
./read_xml.sh: line 22: (-1): substring expression < 0
?[ "x${ATTRIBUTES:(-1):1}x" == "x?x" ] ...
Я не знаю ни одного чистого инструмента синтаксического анализа XML оболочки. Поэтому вам, скорее всего, понадобится инструмент, написанный на другом языке.
Мой модуль Perl XML :: Twig поставляется с таким инструментом:,
xml_grep
где вы, вероятно, напишите, что вы хотитеxml_grep -t '/html/head/title' xhtmlfile.xhtml > titleOfXHTMLPage.txt
(-t
опция дает вам результат в виде текста вместо xml)источник
Другой инструмент командной строки - мой новый Xidel . Он также поддерживает XPath 2 и XQuery, в отличие от уже упомянутого xpath / xmlstarlet.
Название можно прочитать как:
И у него также есть классная функция для экспорта нескольких переменных в bash. Например
устанавливает
$title
заголовок и$imgcount
количество изображений в файле, которые должны быть такими же гибкими, как и анализ непосредственно в bash.источник
Ну, вы можете использовать утилиту xpath. Я думаю, что Perl XML :: Xpath содержит его.
источник
После некоторых исследований по переводу между форматами Linux и Windows путей к файлам в XML-файлах я нашел интересные учебные пособия и решения по следующим вопросам:
источник
Хотя существует довольно много готовых консольных утилит, которые могут делать то, что вы хотите, вероятно, потребуется меньше времени, чтобы написать пару строк кода на языке программирования общего назначения, таком как Python, который вы легко можете расширить и адаптировать к твои нужды.
Вот скрипт Python, который используется
lxml
для анализа - он принимает имя файла или URL-адрес в качестве первого параметра, выражение XPath в качестве второго параметра и печатает строки / узлы, соответствующие данному выражению.Пример 1
lxml
может быть установлен сpip install lxml
. На Ubuntu вы можете использоватьsudo apt install python-lxml
.использование
lxml
также принимает URL в качестве входных данных:Пример 2
Одноразовый скрипт, который служит узкой цели извлечения имен модулей из файла apache maven. Обратите внимание, как перед именем узла (
module
) используется пространство имен по умолчанию{http://maven.apache.org/POM/4.0.0}
:pom.xml :
module_extractor.py :
источник
pip install
кадромapt-get
илиyum
вызова. Спасибо!Метод Yuzem может быть улучшен путем инвертирования порядка
<
и>
знаков вrdom
функции и переменных задания, так что:будет выглядеть так:
Если синтаксический анализ выполняется не так, последний тег в файле XML никогда не будет достигнут. Это может быть проблематично, если вы собираетесь вывести другой файл XML в конце
while
цикла.источник
Это работает, если вы хотите атрибуты XML:
источник
Хотя кажется, что «никогда не анализировать XML, JSON ... из bash без надлежащего инструмента» - это хороший совет, я не согласен. Если это вспомогательная работа, то нужно искать подходящий инструмент, а затем изучать его ... Awk может сделать это за считанные минуты. Мои программы должны работать со всеми вышеупомянутыми и другими видами данных. Черт, я не хочу тестировать 30 инструментов для анализа 5-7-10 различных форматов, которые мне нужны, если я смогу решить проблему за считанные минуты. Мне плевать на XML, JSON или что-то еще! Мне нужно одно решение для всех из них.
Как пример: моя программа SmartHome работает в наших домах. Делая это, он читает множество данных в слишком многих различных форматах, которые я не могу контролировать. Я никогда не использую выделенные, надлежащие инструменты, так как я не хочу тратить больше времени на чтение нужных мне данных. С настройками FS и RS это awk-решение отлично работает для любого текстового формата. Но это может быть неправильным ответом, если ваша основная задача - работать в основном с данными в этом формате!
С проблемой парсинга XML из bash я столкнулся вчера. Вот как я делаю это для любого иерархического формата данных. В качестве бонуса - я назначаю данные непосредственно переменным в скрипте bash.
Чтобы облегчить чтение, я буду представлять решение поэтапно. Из данных теста OP я создал файл: test.xml
Разбор XML в bash и извлечение данных в 90 символов:
Обычно я использую более читаемую версию, поскольку ее легче изменить в реальной жизни, поскольку мне часто приходится тестировать по-другому:
Мне все равно, как называется формат. Я ищу только самое простое решение. В этом конкретном случае я могу видеть из данных, что символ новой строки - это разделитель записей (RS) и поля разделителя <> (FS). В моем исходном случае у меня было сложное индексирование 6 значений в двух записях, связывая их, находя, когда данные существуют, плюс поля (записи) могут или не могут существовать. Потребовалось 4 строки awk, чтобы полностью решить проблему. Итак, адаптируйте идею к каждой потребности, прежде чем использовать ее!
Вторая часть просто смотрит на наличие искомой строки в строке (RS) и, если так, распечатывает необходимые поля (FS). Вышеуказанное заняло у меня около 30 секунд, чтобы скопировать и адаптировать последнюю команду, которую я использовал таким образом (в 4 раза дольше). И это все! Сделано за 90 символов.
Но мне всегда нужно аккуратно помещать данные в переменные в моем скрипте. Сначала я проверяю конструкции так:
В некоторых случаях я использую printf вместо print. Когда я вижу, что все выглядит хорошо, я просто заканчиваю присваивать значения переменным. Я знаю, многие думают, что «eval» - это «зло», не нужно комментировать :) Трюк отлично работает на всех четырех моих сетях в течение многих лет. Но продолжайте учиться, если вы не понимаете, почему это может быть плохой практикой! Моему решению, включая назначения переменных bash и достаточный интервал, для выполнения всех задач требуется 120 символов.
источник