I have an .yml file that configures environment properties of an application, such like this:
env1:
:prop1: "value1"
:prop2: "value2"
...
:propn: "valuen"
env2:
:prop1: "value1"
:prop2: "value2"
:prop3: "value3"
...
:propn: "valuen"
...
envn:
:prop1: "value1"
:prop2: "value2"
...
:propn: "valuen"
I would like to produce a bash script with the following interface:
$ change_env.sh <environment> <property> <new value> <file.yml>
Example:
$ change_env.sh env2 prop3 "this value was changed" file.yml
The output will be:
env1:
:prop1: "value1"
:prop2: "value2"
...
:propn: "valuen"
env2:
:prop1: "value1"
:prop2: "value2"
:prop3: "this value was changed"
...
:propn: "valuen"
...
envn:
:prop1: "value1"
:prop2: "value2"
...
:propn: "valuen"
I found this post, however I could not do it work for my case. Replace an XML element's value? Sed regular expression?
I also tried this: (it fails because alters all properties)
sed 's/\(:pro3:\).*/\1 "new value"/'
Thanks in advance! -- Lourenco.
(very nice first post!)
Try this
cat change_env.sh
#!/bin/bash
# spec : change_env.sh <environment> <property> <new value> <file.yml>
case ${#} in [!4] )
echo "usage: change_env.sh <environment> <property> <new value> <file.yml>" 1>&2
exit 1
;;
esac
env="$1" prop="$2" new="$3" file="$4"
bakFile="${file}".bak
mv "$file" "$bakFile"
sed '/^'"${env}"'/,/^[ ]*$/{ # [ spaceChar tabChar ]
/'"${prop}"'/s/\('"${prop}"'\)\(.*$\)/\1'"${new}"'/
}' "$bakFile" > "$file"
edit
Note, if you expect input to contain white-space in the values you'll want to modify script to quote all variables ("$1","$2"...). (I have now done this, as it is a shell-scripting best practice).
The /env/,/^[{space,tab}]*$/
is a range address for sed. It reads a block of text that contains your environment settings. I'm assuming your sample input is correct and that each env is separated by a blank line. Hmm... this would include the last one in the file.
** edit**
Thanks to @posdef for pointing some problems with this answer. The code is updated to solve the particular case.
Even after the fix, I did notice that given an input like
change_env.sh env2 prop2 "new value" file.yml
The relevant output was
:prop2new value
So, without hardcoding extra :
and space chars into the substitution, this means you'll need to be very verbose in how you call the <property>
value AND the <new value>
, i.e.
change_env.sh env2 ":prop2: " "\"new value\"" file.yml
# note extra cruft-^^-----^^^--^^---------^^--------------
relevant output
env2:
:prop1: "value1"
:prop2: "new value"
:prop3: "value3"
...
:propn: "valuen"
IHTH
I'd use awk:
#!/bin/sh
if [ $# -ne 4 ]; then
echo "usage: $0 env prop value file" >&2
exit 1
fi
awk -F : -v env="$1" -v prop="$2" -v val=" \"$3\"" '
BEGIN {OFS = FS}
$1 == env {in_env = 1}
NF == 0 {in_env = 0}
in_env && $2 == prop {$3 = val}
{print}
' "$4"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With