Как напечатать поля верхнего уровня и поля внутреннего массива вместе, используя jq? - PullRequest
1 голос
/ 23 апреля 2020

У меня есть JSON, который является выходом из AWS CLI.

Пример:

{
  "Volumes": [
    {
      "Tags": [
        {
          "Value": "abc",
          "Key": "Name"
        },
        {
          "Value": "123",
          "Key": "App"
        }
      ],
      "Encrypted": false,
      "VolumeType": "gp2",
      "VolumeId": "vol-123",
      "State": "in-use",
      "Iops": 100,
      "SnapshotId": "snap-123",
      "CreateTime": "2019-08-27T00:51:00.971Z",
      "Size": 20
    },
    {
      "Tags": [
        {
          "Value": "def",
          "Key": "Name"
        },
        {
          "Value": "456",
          "Key": "App"
        }
      ],
      "Encrypted": false,
      "VolumeType": "gp2",
      "VolumeId": "vol-456",
      "State": "in-use",
      "Iops": 100,
      "SnapshotId": "snap-456",
      "CreateTime": "2019-08-27T00:51:00.971Z",
      "Size": 22
    },
{
      "Tags": [
        {
          "Value": "789",
          "Key": "App"
        }
      ],
      "Encrypted": false,
      "VolumeType": "gp2",
      "VolumeId": "vol-789",
      "State": "in-use",
      "Iops": 100,
      "SnapshotId": "snap-789",
      "CreateTime": "2019-08-27T00:51:00.971Z",
      "Size": 23
    }
]
}

Выход будет иметь сотни таких томов в массиве. Я хочу напечатать вывод с полями VolumeId, Size, Name

только при наличии тега Name

Пока что я мог бы сделать что-то вроде:

jq .Volumes | jq '.[] | select(any(.Tags[]; .Key == "Name"))' | jq -r '[.VolumeId,.Size,.Tags[].Key]|join(",")'

This выводит в виде:

vol-123,20,Name,App
vol-456,22,Name,App

Как можно изменить запрос jq, чтобы получить что-то вроде

vol-123,20,abc
vol-456,22,def

Возможно ли это?

ПРИМЕЧАНИЕ. Причина, по которой я пытался это было потому, что мне приходилось делать несколько отчетов / проверок в моем списке томов, начиная с AWS, и я не хотел запускать несколько команд AWS, если результат не изменится. Использование отчетов по одной команде также позволяет избежать любых расхождений, которые могут возникнуть, если некоторые тома будут добавлены / удалены в фоновом режиме при выполнении нескольких команд, например

Ответы [ 3 ]

3 голосов
/ 23 апреля 2020

Если вы используете CLI AWS для описания томов, вы можете использовать параметр --query вместо jq:

aws ec2 describe-volumes --query "Volumes[].[VolumeId,Size,Tags[?Key=='Name'].Value | [0]]" --output text

Для получения информации о синтаксисе см .: Примеры JMESPath - JMESPath

(Приведенная выше команда отлично работала на моей маме c. Если вы используете Windows, возможно, вам придется поиграться с кавычками.)

2 голосов
/ 23 апреля 2020

Если вы все еще ищете решение jq, вы можете сделать это ниже. Просто поместите обязательные поля в массив и вызовите функцию join()

jq -r '.Volumes | map( .VolumeId, .Size, (.Tags[] | select(.Key == "Name").Value)  ) | join(",")'

. Ваше обновленное требование иметь дело с несколькими объектами внутри .Volumes см. Ниже. Удаляя функциональность map(..), мы гарантируем, что поля собираются в отдельные массивы.

Приведенный ниже лог c создает несколько массивов, каждый для одного набора полей запроса, который мы выполняем. Вы можете использовать функцию @csv или join(","), как и раньше.

jq -r '.Volumes[] | [.VolumeId, .Size, (.Tags[] | select(.Key == "Name").Value)] | join(",")' 
0 голосов
/ 23 апреля 2020

Спасибо @Inian за помощь в получении ответа

Последний рабочий фильтр jq для моего запроса:

jq -r '.Volumes[] | select(any(.Tags[]; .Key == "Name")) | [.VolumeId,.Size,(.Tags[] | select(.Key == "Name").Value)]|join(",")'

Вывод будет:

vol-123,20,abc
vol-456,22,def

Отредактировано на основе дальнейших входных данных @Inian. Наконец-то понял, что все это можно передавать по нескольким вызовам jq

...