11

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
oguz ismail
  • 1
  • 16
  • 47
  • 69
Pierre
  • 2,552
  • 5
  • 26
  • 47

2 Answers2

19

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'
Inian
  • 80,270
  • 14
  • 142
  • 161
Mostafa Hussein
  • 11,063
  • 3
  • 36
  • 61
  • 1
    Thanks @Mostafa, this is what I was looking for. I was missing that point: `keys` is a built-in function not a property. Also thanks for the doc link :) – Pierre Mar 21 '19 at 13:44
  • 2
    To make it work I had to write `yq eval '.services | keys' docker-compose.yml` – Kjeld Flarup Feb 01 '21 at 09:46
  • 1
    `yq -r '.services | keys | .[]'` will get you the flat list of services without a YAML list – Sam Gleske May 19 '23 at 17:21
8

Since you just want to list the services from a docker-compose file you could achieve this with a docker-compose command.

docker-compose config --services

Not directly an answer to the question as it is not using yq but maybe it helps ;)

kitingChris
  • 658
  • 6
  • 15
  • `docker-compose config --services` takes over 1 second to load for some reason. interestingly `ruby -e 'require "yaml"; puts YAML.load(File.read("docker-compose.yml"))["services"].keys'` completes in ~0.1s – matti Dec 16 '19 at 18:03
  • while docker-compose config scans the config and might be helpful to check the final configuration that will be applied. In this case I would more stick on the solution from Mostafa Hussein `yq '.services | keys[]' docker-compose.yml` – kitingChris Dec 17 '19 at 19:09
  • 1
    i love this option. Pretty straightforward and it doesn't require `yq` – Andre Leon Rangel Aug 21 '21 at 06:40