Yq: retrieve object keys names

PierreF picture PierreF · Mar 21, 2019 · Viewed 14.7k times · Source

I have a YAML file (docker-compose file in my case) that looks like this:

networks:
    foo:
      some_opts: "covfefe"
    bar:
      some_opts: "such wow"
services:
  apache:
    image: 'apache:1.0.0'
    restart: always
  mysql:
    image: 'mysql:1.0.0'
    restart: always
  php:
    image: 'php'
    restart: always

I would like to extract the services name thanks to yq, an equivalent of jq but for YAML, to have this output:

"apache"
"mysql"
"php"

Currently I can achieve it like this:

$ cat docker-compose.yml | yq '.services' | yq 'keys[]'
"apache"
"mysql"
"php"

Even if it works, the double piped yq seems weird to me. I think I'm doing it wrong.

Question: Is there any way to achieve it with a single yq command ?

I tried this without success, taking inspiration from this question:

$ cat docker-compose.yml | yq '.services.keys[]'
jq: error: Cannot iterate over null

Answer

Mostafa Hussein picture Mostafa Hussein · Mar 21, 2019

keys is a built-in function in jq when given an object, returns its keys in an array. So it is not actually apart of your yaml (not a property) which means you cannot do services.keys.

To get the keys you can do the following when using Python yq:

We will get the object of services in the first part then we pass it to keys which will return a list of keys based on a given object

cat docker-compose.yml | yq '.services | keys'

Or like this (without cat and pipe):

yq '.services | keys' docker-compose.yml

The output will be:

[
  "apache",
  "mysql",
  "php"
]

To get rid of the brackets:

yq '.services | keys[]' docker-compose.yml

The output:

"apache"
"mysql"
"php"

For more about details you can check Builtin operators and functions in jq. Note that yq is a wrapper for jq so the documentation of jq would be helpful as the help of yq recommends.


On Go yq you can do

yq e '.services | keys'