У меня есть этот 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
Что я делаю неправильно?
Не анализируйте вложенные структуры данных комплекса как 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
.
Задание для 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
Как был упомянут, анализирование сложных структурированных данных предпочтительно с соответствующим 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 по умолчанию.
Вы можете на самом деле делать это в 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.
Существует типичное объяснение того, почему sed
и подобные текстовые потоковые инструменты обработки не хорошо оборудованы для парсинга структурированных данных, таких как JSON и XML. У меня нет этого под рукой, но это там, и я полагаю, что точка, что выражения должны были во всех кроме, вероятно, наименьшего количества ситуаций быстро стать очень сложными, в то время как альтернативные инструменты, созданные специально для парсинга структуры, более изящны, читаемы, и эффективны при том же парсинге.
Как muru поместил в комментарий , jq
, должен быть правильный инструмент для задания. Я могу также ручаться за него лично очень счастливый видеть, что он несколько раз заменяет, где я попытался не анализировать те же данные к нет почти никакой или обременил успех. Это даже содержит большое о возможности форматирования и иначе управлять выводом. Я предпочитаю его jsontool
по причине или больше что я в настоящее время забываю.
Командующий Байта , кажется, рекомендует jshon
в другой ответ . Я не использовал тот инструмент, но он напоминает мне о xmlstarlet
и его синтаксис, также с некоторой настраиваемой презентацией для вывода.
Просто другой инструмент 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/
<час>, если не установленный:
npm install -g json
Не высказывание Вас должно использовать 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
распечатайте часть, мы продолжили работать