DavidM
DavidM

Reputation: 13

Trying to use sed to edit a configuration file from a bash script to edit a key/value pair

I have a configuration file that has key/value pairs in it 1 per line that I need to modify from a bash script. It's a bit tricky because there is a specific key/value pair that I need to modify, it may not exist in the file, it may be there but empty, or it may be there but populated already as noted below.

Example snip of the file:

additional.urls=
cache.enable=true
compiler.cache_core=true

I need to find the key/value pair "additional.urls=" and modify it. But nothing is easy, first the line may be populated, or it may not exist at all in the file.

additional.urls=
or
additional.urls=https://myurl.me

If the key/value pair is empty (nothing after the = except perhaps whitespace), then I want to append the url to the end of the line: https://newurl.it:

additional.urls=https://newurl.it

If it's missing all together I want to insert the entire key/value line into the file, preferably at the top but it does not matter too much.

Then it gets trickier, if it already has a value (could be 1 or more urls comma separated) I need to keep everything that is already there and append to the end of the line adding a comma and then the new url:

additional.urls=https://myurl1.me,https://myurl2.me
becomes:
additional.urls=https://myurl1.me,https://myurl2.me,https://newurl.it

I can't figure out how to do this. If it was simply a search and replace I know how to do that but the conditions are driving me nuts. Perhaps sed is not the correct answer, is awk better or something else? I just don't know.

Upvotes: 1

Views: 186

Answers (5)

anubhava
anubhava

Reputation: 784958

You may use this awk solution to meet all 3 conditions:

awk -i inplace -v key='additional.urls' -v val='https://newurl.it' '
BEGIN {
   FS=OFS="="
}
$1 == key {
   $2 = ($2 ~ /^[[:blank:]]*$/ ? "" : $2 ",") val
   p = 1
}
END {
   if (!p)
      print key, val
} 1' file
additional.urls=https://newurl.it
cache.enable=true
compiler.cache_core=true

Upvotes: 0

DevSolar
DevSolar

Reputation: 70243

In an attempt to keep the whole thing readable, not trying to do too much in one statement:

if ! grep -q "additional.urls=" file
then
    # If line does not exist, add it at top.
    sed -i '1s/^/additional.urls=http:\/\/newurl.it\n/' file
else
    #         If value is non-empty, add comma    Append newurl.it to end of the list
    sed -i -e "s/\(additional.urls=.\+\)/\1,/" -e "s/\(additional.urls=.*\)/\1http:\/\/newurl.it/" file
fi

Upvotes: 0

potong
potong

Reputation: 58371

This might work for you (GNU sed):

sed -zEi ':a;
          s#^additional\.urls=.*#&,https://newurl.it#m;
          s/^(additional\.urls=),/\1/m;
          t;
          s/^/additional.urls=\n/;
          ta' file

Slurp the file into memory (-z), engage extended regexps (-E) and edited in-place (-i).

Append ,https://newurl.it to a line beginning additional.urls=.

If the line beginning additional.urls=, exists, remove the ,.

If either of the substitutions were successful, bail out.

Otherwise, insert additional.urls=\n at the start of the file, and repeat.

N.B. The use of the m flag in substitutions for multi-line processing.

The commands may be flattened:

sed -zEi ':a;s#^additional\.urls=.*#&,https://newurl.it#m;s/^(additional\.urls=),/\1/m;t;s/^/additional.urls=\n/;ta' file

Upvotes: 1

pyr0
pyr0

Reputation: 377

sed offers via the e switch to code sh within sed. See the example below and modify for your needs.

First, the matching words will be assigned to variables a and b. Subsequently, they can be used in if and switch statements.

echo -e "foo=\nbar=rab\nzar=raz" | sed -E 's/(.+)=(.*)/ a=\1; b=\2; if [[ $b ]]; then echo "$a=$b"; else case "$a" in foo) echo "$a=oof";; *) echo "$a=$(rev <<< $b)";; esac; fi/e'

Upvotes: 0

Luuk
Luuk

Reputation: 14900

awk -F= -v add="additional.urls=test" '
    { a[$1]=$2 }
    END{ 
       split(add,b,"="); 
       a[b[1]]=(a[b[1]]~/^[[:blank:]]*/ ? "" : a[b[1]]",") b[2]; 
       OFS="="; 
       for(i in a){ print i,a[i] }}' configuration-file

.

cache.enable=true
additional.urls=test
compiler.cache_core=true

Upvotes: 0

Related Questions