Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In jq, get index of current item (similar to Python's enumerate())?

Tags:

json

enumerate

jq

I'm going through a Kubernetes tutorial and am using jq to filter some of kubectl's exhaustive output.

One task that's coming up is to show what images are deployed to what pods, using kubectl get pods. So far I have this:

kubectl get pods -o json | jq '.items[]|[.metadata.name,.spec.containers[].image]'

This gets me output like the this:

[
  "kubernetes-bootcamp-5485cc6795-4blsd",
  "gcr.io/google-samples/kubernetes-bootcamp:v1"
]
[
  "kubernetes-bootcamp-5485cc6795-k824z",
  "gcr.io/google-samples/kubernetes-bootcamp:v1"
]

This is nice, but if I get curious and want to see more information about a specific pod, I'd need to use its index in the .items array. That's fine here where there are only two items in total, but I imagine a production Kubernetes cluster might have thousands. Is there any way I can include the item's index in the output? In other words, I want to see:

[
  0,
  "kubernetes-bootcamp-5485cc6795-4blsd",
  "gcr.io/google-samples/kubernetes-bootcamp:v1"
]
[
  1,
  "kubernetes-bootcamp-5485cc6795-k824z",
  "gcr.io/google-samples/kubernetes-bootcamp:v1"
]

I had tried using path(.) in the array constructor, but it just results in an empty array instead of the path to that item. I've been reading through the jq man page but so far I'm stumped. Any help would be appreciated!

Sample data

Here's a snippet from kubectl that can be used to reproduce the output in my question.

{
    "items": [
        {
            "metadata": {
                "name": "kubernetes-bootcamp-5485cc6795-4blsd"
            },
            "spec": {
                "containers": [
                    {
                        "image": "gcr.io/google-samples/kubernetes-bootcamp:v1"
                    }
                ]
            }
        },
        {
            "metadata": {
                "name": "kubernetes-bootcamp-5485cc6795-k824z"
            },
            "spec": {
                "containers": [
                    {
                        "image": "gcr.io/google-samples/kubernetes-bootcamp:v1"
                    }
                ]
            }
        }
    ]
}

If you save this to output.json for example, you can reproduce my problem with the command

cat output.json | jq '.items[]|[.metadata.name,.spec.containers[].image]' 
like image 800
Dan Passaro Avatar asked Sep 03 '25 16:09

Dan Passaro


2 Answers

You could use the to_entries filter (see the manual) which turns an object into an array of objects containing each field's key and value. However, if applied to an array, the array's indices will be used as keys instead:

.items | to_entries[]
{
  "key": 0,
  "value": ...
}
{
  "key": 1,
  "value": ...
}

Thus, just create your output as before but with .key and .value in mind:

.items | to_entries[] | [.key, .value.metadata.name, .value.spec.containers[].image]
# or
.items | to_entries[] | [.key, (.value | .metadata.name, .spec.containers[].image)]
[
  0,
  "kubernetes-bootcamp-5485cc6795-4blsd",
  "gcr.io/google-samples/kubernetes-bootcamp:v1"
]
[
  1,
  "kubernetes-bootcamp-5485cc6795-k824z",
  "gcr.io/google-samples/kubernetes-bootcamp:v1"
]
like image 112
pmf Avatar answered Sep 05 '25 04:09

pmf


You could create an index variable, e.g. as follows:

range(0; .items|length) as $i | .items[$i] | [$i, .metadata.name, .spec.containers[].image]

Alternatively, you could define a generic enumerate function and use it as follows:

def enumerate(s): foreach s as $x (-1; .+1; [., $x]);

enumerate(.items[] | [.metadata.name, .spec.containers[].image]) | [first] + last
like image 43
peak Avatar answered Sep 05 '25 05:09

peak