JSON – How to Print Path and Key Values

jqjsonsnmpwalk

I would like to print each path and value of a file with included key values line by line. Given the following and , is it also possible to add the values for each line? If not using is there another way? I am thinking of something vaguely similar to for . Also, is there a technical term for what I am trying to do?

$ cat short.json | jq '.'
{
  "Reservations": [
    {
      "Groups": [],
      "Instances": [
        {
          "ImageId": "ami-a",
          "InstanceId": "i-a",
          "InstanceType": "t2.micro",
          "KeyName": "ubuntu"
        }
      ]
    }
  ]
}
$ cat short.json | jq -r '[paths | map(.|tostring) | join(".")]'
[
  "Reservations",
  "Reservations.0",
  "Reservations.0.Groups",
  "Reservations.0.Instances",
  "Reservations.0.Instances.0",
  "Reservations.0.Instances.0.ImageId",
  "Reservations.0.Instances.0.InstanceId",
  "Reservations.0.Instances.0.InstanceType",
  "Reservations.0.Instances.0.KeyName"
]

Example of a single line from the multiline output:
"Reservations.0.Instances.0.ImageId": "ami-a",

Bonus if the output could be formatted to be used in using copy and paste with value easily detached using linux cut:

'.Reservations[].Instances[].ImageId': "ami-a" 
$ cat short.json | jq -r '.Reservations[].Instances[].ImageId'
ami-a

Best Answer

I'm not super knowledgeable on jq but I found this on the interwebs and I think it will work in your case:

Cut and paste version:

jq -r 'paths(scalars) as $p  | [ ( [ $p[] | tostring ] | join(".") ), ( getpath($p) | tojson )] | join(": ")' short.json 

Easy(er) to read version:

jq -r '
paths(scalars) as $p
  | [ ( [ $p[] | tostring ] | join(".") )
    , ( getpath($p) | tojson )
    ]
  | join(": ")
' short.json

Result:

Reservations.0.Instances.0.ImageId: "ami-a"
Reservations.0.Instances.0.InstanceId: "i-a"
Reservations.0.Instances.0.InstanceType: "t2.micro"
Reservations.0.Instances.0.KeyName: "ubuntu"

And because I want the bonus points, here's a hacky sed you can tack on to get the output you want:

... | sed "s/^/\'./; s/:/\':/; s/\.0/[]/g"

Which outputs:

'.Reservations[].Instances[].ImageId': "ami-a"
'.Reservations[].Instances[].InstanceId': "i-a"
'.Reservations[].Instances[].InstanceType': "t2.micro"
'.Reservations[].Instances[].KeyName': "ubuntu"
Related Question