4

As a follow-up to my previous question, I am having trouble getting tags to work right in this type of output. I want to print a table with each property as a row. This is how I expect it to look:

% aws --output table ec2 describe-instances --instance-id $id --query "Reservations[].Instances[0].[{ Property: 'Type', Value: InstanceType }]"         
-------------------------------
|      DescribeInstances      |
+-----------+-----------------+
| Property  |      Value      |
+-----------+-----------------+
|  Type     |  g4dn.12xlarge  |
+-----------+-----------------+

But with tag names it looks like this:

% aws --output table ec2 describe-instances --instance-id $id --query "Reservations[].Instances[0].[{ Property: 'Name', Value: Tags[?Key =='Name'].Value }]"   
-------------------
|DescribeInstances|
+-----------------+
|    Property     |
+-----------------+
|  Name           |
+-----------------+
||     Value     ||
|+---------------+|
||  Elliott-TKD  ||
|+---------------+|

The tag value is correct, but the formatting is weird, and when combined with more other rows the table gets really ugly.

Elliott B
  • 980
  • 9
  • 32

1 Answers1

3

The filter part of your query ([?Key == 'Name']) is creating what JMESPath is describing as a projection.
You will have to reset this projection in order to extract a single string out of it.
Resetting a projection can be achieved using pipes.

Projections are an important concept in JMESPath. However, there are times when projection semantics are not what you want. A common scenario is when you want to operate of the result of a projection rather than projecting an expression onto each element in the array. For example, the expression people[*].first will give you an array containing the first names of everyone in the people array. What if you wanted the first element in that list? If you tried people[*].first[0] that you just evaluate first[0] for each element in the people array, and because indexing is not defined for strings, the final result would be an empty array, []. To accomplish the desired result, you can use a pipe expression, <expression> | <expression>, to indicate that a projection must stop.

Source: https://jmespath.org/tutorial.html#pipe-expressions

So your issue is very close to what they are describing here in the documentation and the reset of that projection can be achieved using:

Tags[?Key =='Name']|[0].Value 

or, with:

Tags[?Key =='Name'].Value | [0]

which are two strictly identical queries.

Given the JSON:

{
  "Reservations": [
    {
      "Instances": [
        {

          "Tags": [
            {
              "Key": "Name",
              "Value": "Elliott-TKD"
            },
            {
              "Key": "Foo",
              "Value": "Bar"
            }
          ]
        }
      ]
    }
  ]
}

The query

Reservations[].Instances[0].[{ Property: `Name`, Value: Tags[?Key == `Name`]|[0].Value }]

Will give the expected

[
  [
    {
      "Property": "Name",
      "Value": "Elliott-TKD"
    }
  ]
]

So it will render properly in your table

------------------------------
|      DescribeInstance      |
+------------+---------------+
|  Property  |     Value     |
+------------+---------------+
|    Name    |  Elliott-TKD  |
+------------+---------------+
β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • Thank you! I started out trying to write a very simple bash script, but now I'm starting to think it would have been easier to write it in Python with boto3. – Elliott B Feb 18 '21 at 21:47