I'm trying to search and replace string from a yaml file that I use for helm values. I have used the following command to extract the values that are different between two files:
diff a.yaml b.yaml|grep ">"|cut -c 3- > new_file.yaml
The a.yaml file contains the following lines:
NAME_VAR: {{ .Data.data.name_var }}
SOME_VALUE: {{ .Data.data.some_value }}
ONE_MORE: {{ .Data.data.one_more }}
and b.yaml this:
NAME_VAR: {{ .Data.data.name_var }}
SOME_VALUE: {{ .Data.data.some_value }}
ONE_MORE: {{ .Data.data.one_more }}
ADD_THIS: {{ .Data.data.<change_me> }}
The output in new_file.yaml gives me the following:
ADD_THIS: {{ .Data.data.<change_me> }}
I need to replace the string inside <change_me> with the key of the output "ADD_THIS" it should look like this:
ADD_THIS: {{ .Data.data.add_this }}
These changes will be updated with vault later automatically in argocd.
I've thought about using awk but I can't seem to replace it.....
Edit
In case you want to replace several fields, e.g.
a.yaml file
NAME_VAR: {{ .Data.data.name_var }}
SOME_VALUE: {{ .Data.data.some_value }}
ONE_MORE: {{ .Data.data.one_more }}
b.yaml file
NAME_VAR: {{ .Data.data.name_var }}
SOME_VALUE: {{ .Data.data. }}
ONE_MORE: {{ .Data.data. }}
ADD_THIS: {{ .Data.data. }}
Using James' answer this is the output:
ADD_THIS: {{ .Data.data.add_this }}
SOME_VALUE: {{ .Data.data.some_value }}
ONE_MORE: {{ .Data.data.one_more }}
SOME_VALUE: {{ .Data.data.some_value }}
ONE_MORE: {{ .Data.data.one_more }}
CodePudding user response:
An awk that frees you from using diff
and grep
and cut
:
$ awk 'NR==FNR{ # process first file, which ever
a[$0] # hash records to a
next # on to the next record
}
{ # process second file
if($0 in a) # if record is in hash (or file 1)
delete a[$0] # remove it from the hash as it is not wanted
else # if record is not in hash (or file 1)
a[$0] # store it to the hash as it is wanted
}
END { # in the end all wanted records are left in the hash
for(i in a) { # go thru all of them
$0=i
sub(/<change_me>/,substr(tolower($1),1,length($1)-1))
print # make the change (above) and output
}
}' [ab].yaml
Output:
ADD_THIS: {{ .Data.data.add_this }}
You could replace the sub
above with
sub(/[^.]*$/,substr(tolower($1),1,length($1)-1),$3)
if the <change_me>
is in fact an arbitrary string.
Edit to solve the issues mentioned in comments:
Now it stores and compares the first fields and compares them ie:
a[SOME_VALUE:]="SOME_VALUE: {{ .Data.data.some_value }}"
Program now:
$ awk 'NR==FNR {
a[$1]=$0
next
}
{
if($1 in a)
delete a[$1]
else
a[$1]=$0
}
END {
for(i in a) {
$0=a[i]
sub(/[^.]*$/,substr(tolower($1),1,length($1)-1),$3)
print
}
}' [ab].yaml
CodePudding user response:
Better use sed for this particular task:
$ sed 's/<change_me>/add_this/' file
ADD_THIS: {{ .Data.data.add_this }}
CodePudding user response:
This takes the value of the first column, lowers it, also removes the colon, then does the replacement.
$ awk '{str = tolower($1)
sub(":", "", str)
sub("<change_me>", str, $0)}1' new_file.yaml
ADD_THIS: {{ .Data.data.add_this }}
CodePudding user response:
If the first column output can be other key values and/or the place holder can vary away from 'change me', awk can use variable names to reference them.
This demo uses an echo to feed the output into awk but the same awk procedure would process a multi-line file with many lines to be substituted, and is not dependent on the key value nor the place holder text.
echo "ADD_THIS: {{ .Data.data.<change_me> }}" | awk ' {n=split($3,parts,"."); sub(parts[n],tolower($1), $3); print $0} ';
result:
ADD_THIS: {{ .Data.data.add_this: }}