Reputation: 13
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
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
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
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
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
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