Разбор JSON на оболочке

11

Как я могу разобрать вывод JSON на оболочке?

Например, Amazon Web Services предоставляет интерфейс командной строки для получения статуса ваших экземпляров:

$ aws ec2 describe-instances <my_instance_id>

Но команда возвращает строку JSON. Вывод этой команды выглядит следующим образом:

$ aws ec2 describe-instances x12345
{
    "Reservations" :
     {  
            "OwnerId": "1345345"
            "Groups": [], 
            "SecurityGroups": [
               {
                  "Foo" : "yes"
                  "Bar" : "no
               }
             ]
     }
}

Существуют ли встроенные оболочки, которые можно использовать для анализа вывода JSON?

Например, я хотел бы зафиксировать в переменной оболочки FOOследующее output["Reservations"]["SecurityGroups"][0]{"Foo"}.

В случае, если это помогает, меня особенно интересуют решения, которые могут работать с Zsh.

Амелио Васкес-Рейна
источник
2
Обычно вы используете инструмент, например, jshon .
Джейсонвриан
1
Используйте, --output textесли вы хотите разобрать в оболочке без использования внешних инструментов, таких как jshon.
Иордания
1
@jasonwryan - Только впервые услышав jshon, я перешел по вашей ссылке Прочитав это, я могу только сказать, что я остался очень доволен, что я случайно услышал и установил jqпервым. Я думаю, что вам, возможно, также захочется услышать об этом, если вы этого еще не сделали - он не беспокоится обо всех этих параметрах командной строки и может выполнять свои собственные регулярные выражения - он даже позволяет вам объявлять функции и переменные, если вы хотите. Смотрите ответ здесь об этом, если вам интересно.
mikeserv

Ответы:

10

Насколько я понимаю, вы ищете значение "Foo". Это действительно легко сделать с помощью инструмента командной строки оболочки jq. Это похоже sedна то, что он реализует свой собственный язык синтаксического анализатора. Учитывая ваш пример:

json='
{
    "Reservations" :
     {  
            "OwnerId" : "1345345",
            "Groups" :  [],
            "SecurityGroups" : [
               {
                  "Foo" : "yes",
                  "Bar" : "no"
               }
             ]
     }
}'

jqможно получить yesтак же просто, как:

printf %s "$json" |
jq '.[].SecurityGroups[0].Foo?'                                                

ВЫВОД

"yes"

Вы можете пройтись по хэшу объекта или списку словаря, используя .dotнотацию, и индексированные массивы можно индексировать проще, используя, как вы уже догадались, числовые индексы в квадратных скобках. В приведенной выше команде я использую пустую форму индекса, чтобы указать, что я хочу, чтобы все итерируемые элементы этого уровня были расширены. Это может быть легче понять следующим образом:

printf %s "$json" | jq '.[][]'

... который разбивает все значения для элементов второго уровня в хэше и получает меня ...

"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]

Это едва царапает поверхность относительно jqвозможностей России. Это чрезвычайно мощный инструмент для сериализации данных в оболочке, он компилируется в один исполняемый двоичный файл в классическом стиле Unix, он очень вероятно доступен через менеджер пакетов для вашего дистрибутива и очень хорошо документирован. Пожалуйста, посетите его gitстраницу и убедитесь сами.

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

printf %s "$json" | jq '..'

{
  "Reservations": {
    "OwnerId": "1345345",
    "Groups": [],
    "SecurityGroups": [
      {
        "Foo": "yes",
        "Bar": "no"
      }
    ]
  }
}
{
  "OwnerId": "1345345",
  "Groups": [],
  "SecurityGroups": [
    {
      "Foo": "yes",
      "Bar": "no"
    }
  ]
}
"1345345"
[]
[
  {
    "Foo": "yes",
    "Bar": "no"
  }
]
{
  "Foo": "yes",
  "Bar": "no"
}
"yes"
"no"

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

mikeserv
источник
10

Это ответ на вашу задачу, но не на ваш вопрос. Это означает, что вы можете достичь своей цели без использования анализатора JSON.

Утилита AWS cli может выводить только выбранные поля, используя --queryаргумент. Это задокументировано здесь .

Например:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[0].GroupName' \
  --instance-id i-6b272337 \
  --output text
mongodb

Вы даже можете выбрать несколько полей, если хотите:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[0].[GroupName,GroupId]' \
  --instance-id i-6b272337 \
  --output text
mongodb sg-710ffa14

И вы можете показать несколько соответствующих структур:

$ aws ec2 describe-instances \
  --query 'Reservations[0].Instances[0].SecurityGroups[*].[GroupName,GroupId]' \
  --instance-id i-6b272337 \
  --output text
mongodb sg-710ffa14
default sg-a0243bcc
Патрик
источник
1
Спасибо! Это очень полезно. Я принимаю @mikeserv главным образом для того, чтобы служить сообществу с ответом на вопрос, но я буду использовать ваш ответ
Амелио Васкес-Рейна,
Это очень полезно! Большое спасибо!!
Доктор медицины Саим Ахмед