Home > Back-end >  replace string from one file to another awk
replace string from one file to another awk

Time:11-18

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 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: }}
  • Related