Regex с sed управляют для парсинга json текста

У меня есть этот json текст:

{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

Я хочу извлечь полное состояние buildStatus, т.е. ожидаемым выводом была "ОШИБКА"

"buildStatus" : {
    "status" : "ERROR",
    ....
}

Я попробовал sed выражение ниже, но оно не работает, оно возвращается OK:

status= sed -E 's/.*\"buildStatus\":.*\"status\":\"([^\"]*)\",.*/\1/' jsonfile

Что я делаю неправильно?

15
задан 23 December 2016 в 07:29

7 ответов

Не анализируйте вложенные структуры данных комплекса как JSON или XML с регулярными выражениями, используйте надлежащий синтаксический анализатор JSON, как jshon.

Первый необходимо установить его:

sudo apt-get install jshon

Затем необходимо предоставить ему данные JSON для парсинга через стандартный вход, таким образом, можно или перенаправить вывод другой команды там с каналом (|) или перенаправить файл к нему (< filename).

аргументы это должно извлечь данные, которые Вы хотите, похожи на это:

jshon -e "buildStatus" -e "status" -u
  • -e "buildStatus" выборы элемент с "buildStatus" индексируют из высокоуровневого словаря.
  • -e "status" выборы элемент с "состоянием" индексируют из второго словаря уровня, выбранного выше.
  • -u преобразовывает выбранные данные от JSON до простых данных (т.е. здесь это удаляет кавычки вокруг строки)

Так команда, которую Вы выполняете, в зависимости от того, где Вы получаете данные из, похож на одного из тех:

jshon -e "buildStatus" -e "status" -u < YOUR_INPUT_FILE
YOUR_JSON_PRODUCING_COMMAND | jshon -e "buildStatus" -e "status" -u

Для получения дополнительной информации jshon можно прочитать его страницу справочника, доступную онлайн здесь или путем простого ввода man jshon.

16
ответ дан 23 November 2019 в 02:38

Задание для jq:

jq -r '.["buildStatus"]["status"]' file.json

Может быть сокращен к:

jq -r '.buildStatus.status' file.json

-r (--raw-output) выводы строка без json строковое форматирование т.е. без кавычек.

Пример:

% cat file.json                   
{
    "buildStatus" : {
        "status" : "ERROR",
        "conditions" : [{
                "status" : "OK",
                "metricKey" : "bugs"
            }, {
                "status" : "ERROR",
                "metricKey" : "test_success_density"
            }, {
                "status" : "OK",
                "metricKey" : "vulnerabilities"
            }
        ],
        "periods" : []
    }
}

% jq -r '.["buildStatus"]["status"]' file.json
ERROR

% jq -r '.buildStatus.status' file.json       
ERROR
<час>

, Если не установленный уже, установите его (доступный в репозитории Вселенной):

sudo apt-get install jq 
10
ответ дан 23 November 2019 в 02:38

Как был упомянут, анализирование сложных структурированных данных предпочтительно с соответствующим API. Python имеет json модуль для этого, которое я лично использую довольно много в своих сценариях, и довольно легко извлечь желаемые поля, которые Вы хотите как так:

$ python -c 'import sys,json;print json.load(sys.stdin)["buildStatus"]["status"]' <  input.txt
ERROR

, Что происходит, вот то, что мы перенаправляем входной файл к stdin Python и читаем это с json.load(). Это становится словарем Python с ключом "buildStatus", и он содержит другой словарь Python с ключом "состояния". Таким образом мы, просто распечатывают значение ключа в словаре, который хранится в рамках другого словаря. Довольно простой.

Кроме простоты, другое преимущество состоит в том, что Python и этот API все предварительно устанавливаются и идутся Ubuntu по умолчанию.

8
ответ дан 23 November 2019 в 02:38

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

Теперь, в Вашем простом примере, все, что Вы хотите, является первым вхождением "status", таким образом, Вы могли сделать:

$ sed -nE '/status/{s/.*:\s*"(.*)",/\1/p;q}' file.json 
ERROR

прием должен использовать -n, чтобы не печатать, затем если строка соответствует status (/status/), Вы удаляете все кроме части, которую Вы хотите s/.*:\s*"(.*)",/\1/, p rint строка и q uit.

<час>

Лично, я нахожу эту эквивалентную команду grep намного более простой:

$ grep -m1 -oP '"status"\s*:\s*"\K[^"]+' file.json 
ERROR

Или этот:

$ perl -ne 'if(s/.*"status"\s*:\s*"([^"]+).*/$1/){print;exit}' file.json 
ERROR

Серьезно, хотя, если Вы планируете проанализировать файлы JSON, не пытаются сделать это вручную. Используйте надлежащий синтаксический анализатор JSON.

6
ответ дан 23 November 2019 в 02:38

Существует типичное объяснение того, почему sed и подобные текстовые потоковые инструменты обработки не хорошо оборудованы для парсинга структурированных данных, таких как JSON и XML. У меня нет этого под рукой, но это там, и я полагаю, что точка, что выражения должны были во всех кроме, вероятно, наименьшего количества ситуаций быстро стать очень сложными, в то время как альтернативные инструменты, созданные специально для парсинга структуры, более изящны, читаемы, и эффективны при том же парсинге.

Как muru поместил в комментарий , jq, должен быть правильный инструмент для задания. Я могу также ручаться за него лично очень счастливый видеть, что он несколько раз заменяет, где я попытался не анализировать те же данные к нет почти никакой или обременил успех. Это даже содержит большое о возможности форматирования и иначе управлять выводом. Я предпочитаю его jsontool по причине или больше что я в настоящее время забываю.

Командующий Байта , кажется, рекомендует jshon в другой ответ . Я не использовал тот инструмент, но он напоминает мне о xmlstarlet и его синтаксис, также с некоторой настраиваемой презентацией для вывода.

0
ответ дан 23 November 2019 в 02:38

Просто другой инструмент Json, названный json ( https://github.com/trentm/json)

$ json buildStatus.status < file.json
ERROR

Это тематическое исследование, вводит в заблуждение: похоже, что инструменты не работают. Можно также использовать json для изменения json файлы:

$ json -e 'this.buildStatus.status="not error"' < file.json > new.json

или даже...

$ json -e 'this.buildStatus.status="no errors"' < file.json | json -e 'this.buildStatus.status
no errors

документация в: http://trentm.com/json/

<час>

, если не установленный:

  • узел установки
  • и sudo npm install -g json
0
ответ дан 23 November 2019 в 02:38

Не высказывание Вас должно использовать sed (Я думаю, что у кого-то есть downvoted меня только для того, чтобы не записать обязательный протест), но, если необходимо искать что-то на следующей строке к buildStatus поскольку Вы, кажется, пробуете в своей собственной попытке, необходимо сказать sed считать следующую строку с N команда

$ sed -rn '/buildStatus/N;s/.*buildStatus.*\n.*: "(.*)",/\1/p' file
ERROR

Примечания:

  • -n ничего не печатайте, пока мы не попросим его
  • -r используйте ДО (то же как -E)
  • /buildStatus/N найдите этот шаблон и считайте следующую строку также
  • s/old/new/ замена old с new
  • .* любое количество любых символов на строке
  • \n новая строка
  • : "(.*)", сохраните любые символы, происходящие между : " и ",
  • \1 обратная ссылка на сохраненный шаблон
  • p распечатайте часть, мы продолжили работать
6
ответ дан 23 November 2019 в 02:38

Другие вопросы по тегам:

Похожие вопросы: