Liquid Penguin
Liquid Penguin

Reputation: 311

Using sed for a generic substitutioner

I am being handed a file that has different configuration entries Lines from example input:

       "configuration_name_1": "configuration_value_1"
  configuration_name_2 : configuration_value_2 
  "configuration_name_3": 'configuration_value_3'
  "configuration_name_4": configuration_value_4

These values are supposed to act as substitutes in different files (by location and type- JSON, yaml, etc). There is no way to implement a unified file type for the whole solution and adding additional tools to the host is out of the question.

I have managed to trim all of the configurations to a key:value format in a temporary file. Example:

configuration_name_1:configuration_value_1
configuration_name_2:configuration_value_2 
configuration_name_3:configuration_value_3

The next step is to override values in different files. example.yaml file contains (keep in mind, yaml is indentation-sensitive):

  configuration_name_1: "test"
  configuration_name_2:  123 

example.yaml must be changed to :

  configuration_name_1: "configuration_value_1"
  configuration_name_2:  configuration_value_2

example.json contains

{
 "configuration_name_3": "abcd"
 "configuration_name_4":  5555
}

example.json must be changed to :

{
 "configuration_name_3": "configuration_value_3"
 "configuration_name_4":  configuration_value_4
}

Is there a way to override the the values for the specific keys in the target files, while ignoring the formatting?

Upvotes: 0

Views: 60

Answers (1)

Ed Morton
Ed Morton

Reputation: 204721

sed is for doing simple s/old/new on individual strings, that is all. For anything else you should be using awk, e.g. with GNU awk for gensub() and the third arg to match():

$ cat tst.awk
NR == FNR {
    tag = gensub(/:.*/,"",1)
    val = gensub(/[^:]+:/,"",1)
    gsub(/^\s*["\047]?|["\047]?\s*$/,"",tag)
    gsub(/^\s*["\047]?|["\047]?\s*$/,"",val)
    tag2val[tag] = val
    next
}
match($0,/^(\s*([^:]+)[:[:space:]]+)(.*)$/,a) {
    tag = a[2]
    gsub(/^"|"$/,"",tag)
    if ( tag in tag2val ) {
        delim = (gsub(/^"|"$/,"",a[3]) ? "\"" : "")
        $0 = a[1] delim tag2val[tag] delim
    }
}
{ print }

$ cat foo.map
       "configuration_name_1": "configuration_value_1"
  configuration_name_2 : configuration_value_2
  "configuration_name_3": 'configuration_value_3'
  "configuration_name_4": configuration_value_4

$ awk -f tst.awk foo.map example.yaml example.json
  configuration_name_1: "configuration_value_1"
  configuration_name_2:  configuration_value_2
{
 "configuration_name_3": "configuration_value_3"
 "configuration_name_4":  configuration_value_4
}

and to make the changes "inplace" if that's what you want:

$ cat example.yaml
  configuration_name_1: "test"
  configuration_name_2:  123

$ cat example.json
{
 "configuration_name_3": "abcd"
 "configuration_name_4":  5555
}

$ awk -i inplace -f tst.awk foo.map example.yaml example.json

$ cat example.yaml
  configuration_name_1: "configuration_value_1"
  configuration_name_2:  configuration_value_2

$ cat example.json
{
 "configuration_name_3": "configuration_value_3"
 "configuration_name_4":  configuration_value_4
}

Upvotes: 2

Related Questions