You can use the field [+] notation to append fields in yq v3. So your command results in
yq --style double w -i myfile.yaml 'spec.template.spec.containers[0].command[+]' "c"
The above command appends the entry "c" to the array.
Or if you want to update the whole array command you could do in v4. Note that this creates the array entries in separate lines than what is shown in the OP. See YAML Multi-Line Arrays
yq e '.spec.template.spec.containers[0].command |= ["a", "b", "c","d"] | ..style="double"' yaml
Note that yq v4 is already out there and supports much powerful path expressions and operations. See Upgrading from v3 for instructions
Answer from Inian on Stack Overflow[question][solved]: how do I add to an array contents from another file
Syntax to write and append array with v4
How to Add / Replace array elements with "yq" conditionally - Stack Overflow
yq syntax to append a modified array element to a YAML file - Stack Overflow
Use this:
yq -i '.persons[0].city = "Barcelona"' yourfile.yaml
replacing “Barcelona” and yourfile.yaml as appropriate. This replaces the value of city inside the first element of the persons array (or creates it if there is none).
Alternatively, if you dont know the exact index, but know the name of the object you could try this:
yq -i '.persons[] |= select(.name == "mario").city = "Barcelona"' yourfile.yaml
works in yq version 4.25.2
UPDATE based on comments (Kusalananda), for versions 4.3x and 4.4x you need to use the following:
yq4407 -i '.persons |= map(select(.name == "mario").city = "Barcelona")' city.yaml
I don't have enough rep to comment on your answer @kev - but that is super neat. I'm going to clean it up a little and put it into the tips and tricks in the yq docs.
I've made it a little more generic and put it all in one command:
yq ea '.services = (
((.services[] | {.name: .}) as $item ireduce ({}; . * $item )) as $uniqueMap
| ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value)
) | select(fi==0)' *.yaml
Disclosure: I wrote yq
ireduce({}; . * $item)- create an objectireduce([]; . + $item)- create an array
yq ea '(.services[] | {.name: .url}) as $item ireduce ({}; . * $item ) | to_entries' Master.yaml service*.yaml |
yq e '{"services": .[] as $item ireduce([]; . + {"name": $item.key, "url": $item.value})}' -
read more
I just realized that my solution only worked for kislyuk/yq.
yq -y '.set += (.set | map(select(.x == "a") | .x = "A"))'
For mikefarah/yq go with @Fravadona's solution
yq '.set as $set | .set += ($set | map(select(.x=="a") | .x = "A"))'
Both output:
set:
- x: a
y: aaa
- x: b
y: bbb
- x: a
y: ccc
- x: A
y: aaa
- x: A
y: ccc
I opened an issue on github. Mike identified the cause as:
[yq] does not create a copy of the data structure when you call
.set[]. In the expression where you use it twice, the elements of the splat refer to the same location in memory, so updating one updates both.To get what you need in yq, you need to explicitly make a copy, you can do that by merging it in to an empty node
His suggestion changes my code:
old: yq '{"set":[.set[], ( .set[] |select(.x=="a")|.x="A")]}'
new: yq '{"set":[.set[], (({}*.set[])|select(.x=="a")|.x="A")]}'
^^^^^^^^^^^
Given that running kislyuk/yq on my original code produces the result I expected, I think the root cause of my problem is not having appropriate sequence points for use of / assignment to .set[].