Несколько уровней массива рендеринга json с помощью jq

Вот вывод all-ec2-instance.json из ec2-describe-instances:

{
    "Reservations": [
        {
            "OwnerId": "",
            "ReservationId": "",
            "Groups": [],
            "Instances": [
                {

                    "InstanceId": "i-11111111",
                    "Hypervisor": "xen",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/sda1",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": false,
                                "VolumeId": "vol-11111111",
                                "AttachTime": "2016-04-19T15:53:53.000Z"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdf",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": false,
                                "VolumeId": "vol-22222222",
                                "AttachTime": "2016-05-25T08:22:33.000Z"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdg",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": false,
                                "VolumeId": "vol-33333333",
                                "AttachTime": "2016-02-28T04:22:07.000Z"
                            }
                        }
                    ],
                     "Tags": [
                        {
                            "Value": "ec2-test1",
                            "Key": "Name"
                        }
                    ]
                }
            ]
        },
        {
            "OwnerId": "",
            "ReservationId": "",
            "Groups": [],
            "Instances": [
                {

                    "InstanceId": "i-22222222",
                    "Hypervisor": "xen",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/sda1",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": false,
                                "VolumeId": "vol-44444444",
                                "AttachTime": "2016-05-19T15:53:53.000Z"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdf",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": false,
                                "VolumeId": "vol-55555555",
                                "AttachTime": "2015-08-25T08:22:33.000Z"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdg",
                            "Ebs": {
                                "Status": "attached",
                                "DeleteOnTermination": false,
                                "VolumeId": "vol-66666666",
                                "AttachTime": "2016-07-28T04:22:07.000Z"
                            }
                        }
                    ],
                     "Tags": [
                        {
                            "Value": "ec2-test2",
                            "Key": "Name"
                        }
                    ]
                }
            ]
        }
    ]
}

Это еще один вопрос из предыдущего ответа, данного https://stackoverflow.com/a/39204803/567761. Теперь я могу использовать следующий синтаксис для получения значения тега экземпляра, а также идентификатора тома EBS:

cat all-ec2-instance.json |jq -r '.Reservations[] | .Instances[] |  .Tags[].Value  +" "+ .BlockDeviceMappings[].Ebs.VolumeId '

но если я захочу получить другое значение из массива BlockDeviceMappings, я получу неправильный результат, что означает, что я не смогу правильно отобразить значение массива другого уровня, например, значение тега и VolumeId и DeviceName, я все равно получу избыточный вывод. Я старался:

cat all-ec2-instance.json |jq -c -r '.Reservations[] | .Instances[] |  .Tags[].Value +" "+ .BlockDeviceMappings[].Ebs.VolumeId +" "+ .BlockDeviceMappings[].DeviceName '

Я получу результат 16, что неверно, предположим, что будет только 6. Если взять только VolumeId и DeviceName, которые находятся в массиве одного уровня BlockDeviceMappings, мы можем сделать это:

cat all-ec2-instance.json |jq -c -r '.Reservations[] | .Instances[] |  .BlockDeviceMappings[] |.Ebs.VolumeId +" "+ .DeviceName '

Как в jq сохранить значение предыдущего уровня массива и присвоить его более позднему циклу массива? Я пытался использовать переменные и другие функции jq, но безуспешно :(

Вот желаемый результат (запятая или любой другой разделитель в порядке):

ec2-test1,vol-11111111,/dev/sda1
ec2-test1,vol-22222222,/dev/sdf
ec2-test1,vol-33333333,/dev/sdg
ec2-test2,vol-44444444,/dev/sda1
ec2-test2,vol-55555555,/dev/sdf
ec2-test2,vol-66666666,/dev/sdg

person sylye    schedule 14.10.2016    source источник
comment
Было бы полезно, если бы ваш вопрос включал в себя желаемый результат запроса, который вы собираетесь создать, — это упростит определение правильности данного ответа и уменьшит неуместное внимание к конкретному механизму, который вы в настоящее время предполагаете использовать для построения этого запроса. (что, как правило, указывает на проблему XY).   -  person Charles Duffy    schedule 14.10.2016


Ответы (2)


Я сделаю еще один ответ для работы с jq

Сначала вы можете переписать первый запрос

cat all-ec2-instance.json \
| jq -r '.Reservations[].Instances[] | .Tags[].Value +" "+ .BlockDeviceMappings[].Ebs.VolumeId'

Затем, если вы хотите добавить дополнительное значение из Json, например `DeviceName``

cat all-ec2-instance.json \
| jq -r '.Reservations[].Instances[] | .Tags[].Value +" "+(.BlockDeviceMappings[] | .Ebs.VolumeId +" "+ .DeviceName)'

вы получаете следующее

"ec2-test1 vol-11111111 /dev/sda1"
"ec2-test1 vol-22222222 /dev/sdf"
"ec2-test1 vol-33333333 /dev/sdg"
"ec2-test2 vol-44444444 /dev/sda1"
"ec2-test2 vol-55555555 /dev/sdf"
"ec2-test2 vol-66666666 /dev/sdg"

какие 6 строк вы ожидаете

person Frederic Henri    schedule 14.10.2016
comment
Это работает! Но я не могу найти использование круглых скобок в руководстве по jq, поэтому никогда не узнаю, что мы можем использовать это для создания другого изолированного цикла массива. Где в руководстве jq я могу найти использование круглых скобок (и как создать изолирующий цикл)? Я использую это руководство: stedolan.github.io/jq/manual - person sylye; 21.10.2016
comment
это зависит от того, что вы хотите сделать, но поскольку вы хотели объединить строки, вам нужны круглые скобки (например, математический метод), которые вы можете проверить в полном руководстве, есть несколько примеров, в которых используются круглые скобки, но у них нет специальной главы, посвященной их обычаи - person Frederic Henri; 21.10.2016

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

получить значение тега экземпляра, а также объемный идентификатор EBS:

aws ec2 describe-instances --query "Reservations[].Instances[].[BlockDeviceMappings[].Ebs.VolumeId, Tags[].Value]"

Если вы хотите расширить, чтобы получить поле DeviceName

aws ec2 describe-instances --query "Reservations[].Instances[].[BlockDeviceMappings[].[DeviceName, Ebs.VolumeId], Tags[].Value]"

и если вы хотите сохранить текст (когда вы запускаете необработанные данные из jq), вы можете добавить флаг --output text в команду CLI

person Frederic Henri    schedule 14.10.2016
comment
да это я понял. но я хочу знать, как решить это с помощью bash, так как в будущем мне нужно будет иметь дело с другим файлом json. Однако ваш вклад также приветствуется! - person sylye; 14.10.2016
comment
Язык запросов, который использует CLI, также имеет инструмент командной строки, jp - person Jordon Phillips; 14.10.2016
comment
@JordonPhillips Я думаю, что ОП имел в виду, что он захочет работать с файлом JSon, который может быть получен в результате работы AWS CLI или чего-то еще. - person Frederic Henri; 15.10.2016
comment
Да, но jmespath не ограничивается интерфейсом aws. Это открытая спецификация, реализованная на нескольких языках программирования (ruby, php, python, javascript, java, lua, rust и т. д.) и имеющая инструмент командной строки, который можно использовать так же, как jq. Таким образом, даже если вы беспокоитесь об использовании запросов за пределами aws cli, jmespath все равно будет лучшим выбором. - person Jordon Phillips; 16.10.2016
comment
Спасибо @JordonPhillips, я знал, что это jmespath, но я не знал об инструменте командной строки. - person Frederic Henri; 16.10.2016