Как найти информацию внутри тега xml с помощью grep?

Я работаю над оболочкой linux script, чтобы найти информацию в XML файле, используя grep. Я нахожусь на mac, который, я надеюсь, не имеет большого значения.

Чтобы найти нужную информацию, я запускаю:

grep -oP "<title>(.*)</title>" temp.xml

Я получаю взамен список совпадений, и это включает тег <title>.

Как получить список с только информацией внутри тега title, но без тега title с помощью grep?

Ответ 1

Я не понимаю, почему вы хотите использовать grep для этого, в то время как его можно решить с помощью тривиального выражения XPath:

//title/text()

Есть много инструментов командной строки для XPath, и они обычно связаны с ОС.

Ответ на этот вопрос о переполнении стека содержит ряд таких инструментов.

Проблема с grep заключается в том, что это общий инструмент для обработки текста, и он не знает какой-либо структуры XML. Для очень простого сценария вы можете заставить его работать. Если документ сложный или если вы используете его в script, который выдержит месяцы или годы, а не только одноразовую работу, вы можете почувствовать сожаление о результатах.

XPath позволяет легко определить разницу между похожими тегами, которые отображаются в разных контекстах документа.

<article>
    <author>
        <name>Jon Doe</name>
        <title>Chief Editor</title>
    </author>
    <title>On the Benefits of grep</title>
    <publicationDate>2018-02-12</publicationDate>
    <text>blah blah blah</text>
</article>

Извлечение заголовка статьи, представленной этим документом, с помощью grep не удастся, если вы использовали любой из других ответов, размещенных здесь. Вы можете технически написать регулярное выражение, чтобы получить то, что вам нужно, но это намного проще с XPath.

/article/title/text()

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

Ответ 2

Поскольку вы уже используете grep -P, почему бы вам не использовать его функции?

grep -oP '(?<=<title>).*?(?=</title>)'

В общем случае XPath - правильное решение, но для игрушечных сценариев, да, Вирджиния, это можно сделать.

Ответ 3

Это не лучшее решение, я бы искал XML lib в bash, но вы можете сделать:

grep -oP "<title>(.*)</title>" temp.xml | cut -d ">" -f 2 | cut -d "<" -f 1

Ответ 4

Вы можете установить xgrep с помощью xpath, как предложено в Tom answer

man xgrep

Ответ 5

grep -oP "<foo>(.*)</foo>" "XML.xml" | sed -n 's/.*<foo>\([^<]*\)<\/foo>.*/\1/p' >> "foo.txt"