Replace value in yaml if name : xxx with bash
Asked Answered
H

3

8

I want to change yaml file value based on name:

Example:

spec:
  containers:
    - name: app1
      image: imageurl.com
      command: []
      env:
      - name: MONGO_HOST
        value: localhost

Here you can see we have added an env for mongo host. Now using BASH i want to change MONGO_HOST value based on condition like if - name: MONGO_HOST set value: 172.16.87.98

Hatshepsut answered 27/1, 2020 at 8:19 Comment(1)
Install a YAML-aware tool like yq.Fullmouthed
K
4

Sed requires knowing if there is indeed MONGO_HOST on that file so grep comes into the solution.

 if grep -Fq -- "- name: MONGO_HOST" file.yaml; then
   sed 's/^\([[:space:]]\+value:\).*/\1 172.16.87.98/' file.yaml
 fi

The if-statement is from the shell, which checks if grep really found a pattern/regexp and execute sed in this case.

The -F means grep is looking for fixed strings, not BRE (basic regular expression) nor ERE (extended regular expression)

The -q means quiet or silence the output.

The -- means end of options, because options usually starts with a dash - anything after the -- grep will not treat it as an option anymore

If there is/are more than one string value: with the regexp in that file.yml sed will replace em all. But as suggested already use the proper tool for parsing/editing yaml file.

Edit: as pointed out by Ranvijay Sachan sed can check if a pattern is there and replace the following line.

Using the command based file editor ed

printf '%s\n' '/MONGO_HOST/+1s/^\([[:space:]]\+value:\).*/\1 172.16.87.98/' ,p w | ed -s file.yaml
Kickback answered 27/1, 2020 at 13:15 Comment(5)
This will replace only next line i believesed -i '/MONGO_HOST/{n;s/^\([[:space:]]\+value:\).*/\1 172.16.87.98/}' file.yaml and thank you for the solution i was looking exactly same.Hatshepsut
Just one comment that it will edit yaml file if - name: MONGO_HOST string is found anywhere in the file not just in the previous line of value: string.Bailey
Indeed @BaileyKickback
@Bailey the ed solution will only edited in place what is intended which is the next line after MONGO_HOSTKickback
Indeed, ed solution is very nice +1Bailey
A
18

kislyuk/yq is a YAML syntax aware parser which uses jq as its JSON processor. yq takes YAML input, converts it to JSON, and feeds it to jq

The filter, the part under '..' is applied on the JSON object, and the resulting JSON with the IP updated is formed and it is converted back to YAML format, because of the -y argument.

yq -y '(.spec.containers[].env[]|select(.name == "MONGO_HOST").value)|="172.16.87.98"' yaml  

Installation and usage is pretty straightforward which is available in yq: Command-line YAML/XML processor

You can use the in-place edit option -i just like sed -i to avoid re-directing to a temporary file with yq -yi '...'


mikefarah/yq

mikefarah/yq is a Go implementation of the YAML parser which since v4 has adopted a DSL similar to that of jq. So using the same, one could do

yq e '(.spec.containers[].env[]|select(.name == "MONGO_HOST").value) |= "172.16.87.98"' yaml
Amphitropous answered 27/1, 2020 at 8:38 Comment(3)
in my machine box if i type yq i see only eval and eval-all commands only . how is this different from the above parserSchear
@KishoreKumar: You have the mikefarah/yq installed then. The eval is abbreviated to e in my code aboveAmphitropous
So the -y option is used to retain to yaml format? I don't have this option in helpMasterstroke
K
4

Sed requires knowing if there is indeed MONGO_HOST on that file so grep comes into the solution.

 if grep -Fq -- "- name: MONGO_HOST" file.yaml; then
   sed 's/^\([[:space:]]\+value:\).*/\1 172.16.87.98/' file.yaml
 fi

The if-statement is from the shell, which checks if grep really found a pattern/regexp and execute sed in this case.

The -F means grep is looking for fixed strings, not BRE (basic regular expression) nor ERE (extended regular expression)

The -q means quiet or silence the output.

The -- means end of options, because options usually starts with a dash - anything after the -- grep will not treat it as an option anymore

If there is/are more than one string value: with the regexp in that file.yml sed will replace em all. But as suggested already use the proper tool for parsing/editing yaml file.

Edit: as pointed out by Ranvijay Sachan sed can check if a pattern is there and replace the following line.

Using the command based file editor ed

printf '%s\n' '/MONGO_HOST/+1s/^\([[:space:]]\+value:\).*/\1 172.16.87.98/' ,p w | ed -s file.yaml
Kickback answered 27/1, 2020 at 13:15 Comment(5)
This will replace only next line i believesed -i '/MONGO_HOST/{n;s/^\([[:space:]]\+value:\).*/\1 172.16.87.98/}' file.yaml and thank you for the solution i was looking exactly same.Hatshepsut
Just one comment that it will edit yaml file if - name: MONGO_HOST string is found anywhere in the file not just in the previous line of value: string.Bailey
Indeed @BaileyKickback
@Bailey the ed solution will only edited in place what is intended which is the next line after MONGO_HOSTKickback
Indeed, ed solution is very nice +1Bailey
B
3

You may use this awk:

awk '/^[ \t]*- *name: *MONGO_HOST[ \t]*$/{p=NR}
p && NR==p+1{sub(/value:.+/, "value: 172.16.87.98")} 1' file.yml

spec:
  containers:
    - name: app1
      image: imageurl.com
      command: []
      env:
      - name: MONGO_HOST
        value: 172.16.87.98

However, please keep in mind that it is usually better to use dedicated yaml parsers for this.

Bailey answered 27/1, 2020 at 8:27 Comment(2)
sed will require knowing if there is indeed - name: MONGO_HOST so sed alone can't do that.Kickback
@RanvijaySachan: awk is readily available on all Unix/Linux or on Windows. So suggest you to consider using that only.Bailey

© 2022 - 2024 — McMap. All rights reserved.