'yq syntax to append a modified array element to a YAML file
Given a YAML file like:
set:
- x: a
y: aaa
- x: b
y: bbb
- x: a
y: ccc
I want to select elements of set where x==a, manipulate them, and append the result to the original array. For example:
set:
- x: a
y: aaa
- x: b
y: bbb
- x: a
y: ccc
- x: A
y: aaa
- x: A
y: ccc
I found Mike Farah's version of yq and tried:
yq '{"set":[.set[], (.set[]|select(.x=="a")|.x="A")]}'
but this changes the original, resulting in:
set:
- x: A
y: aaa
- x: b
y: bbb
- x: A
y: ccc
- x: A
y: aaa
- x: A
y: ccc
Solution 1:[1]
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
Solution 2:[2]
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[].
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 |
