I have a big YAMl file and i need to select all top mapping keys, that have other mapping key under them. It would be great if i could done parsing with yq, but other solutions are welcome too For example, i have yaml file
foo:
bar:
- "hello"
quz:
bar:
- "hi"
der:
boo: true
and i need to select just foo
and bar
so my final yaml will look like this:
foo:
bar:
- "hello"
quz:
bar:
- "hi"
I already tried something like this, it is do nothing test.yaml contains example above
yq eval 'select(.[] | has("bar"))' test.yml
yq eval 'select(.[] | .bar != null)' test.yml
And i generally do not understand why using query without select gives me correct boolean output
yq eval '.[] | has("bar")' test.yml
true
true
false
With .[] | has("bar")
you get the booleans you would use in a wrapping select
expression, but you're missing that .[]
destructures the outer map (to generate the booleans) while select
is still applied to the whole map (as it's in the outer context).
One way to achieve what you want is using with_entries
, which takes a function that is provided access to each .key
and .value
, but retains the outer structure:
yq 'with_entries(select(.value | has("bar")))'
Another way could be to use the pick
function, which takes a list of keys to keep. Generate that list by applying your original filter, and extracting each key
from the matches (while using map
instead of .[]
to retain the array):
yq 'pick(map(select(has("bar")) | key))'
Both output:
foo:
bar:
- "hello"
quz:
bar:
- "hi"
Tested with mikefarah/yq version v4.35.1. Note that since version v4.18.1, the eval
/e
command is the default, and can be omitted. (As an aside, the with_entries
approach should also work as is using kislyuk/yq.)