smihael smihael - 4 months ago 23
Ini Question

Reading value from an ini style file with sed/awk

I wrote a simple bash function which would read value from an ini file (defined by variable

CONF_FILE
) and output it

getConfValue() {
#getConfValue section variable
#return value of a specific variable from given section of a conf file
section=$1
var="$2"
val=$(sed -nr "/\[$section\]/,/\[/{/$var/p}" $CONF_FILE)
val=${val#$var=}
echo "$val"
}


The problem is that it does not ignore comments and runs into troubles if multiple variables within a section names share common substrings.

Example ini file:

[general]
# TEST=old
; TEST=comment
TEST=new
TESTING=this will be output too
PATH=/tmp/test


Running
getConfValue general PATH
would output
/tmp/test
as expected, but running
getConfValue general TEST
shows all the problems this approach has.

How to fix that?

I know there are dedicated tools like
crudini
or tools for python, perl and php out in the wild, but I do not want to add extra dependencies for simple config file parsing. A solution incorporating awk instead of sed would be just fine too.

Answer

Sticking with sed you could anchor your var search to the start of the record using ^ and end it with an equal sign:

"/\[$section\]/,/\[/{/^$var=/p}"

If you are concerned about whitespace in front of your record you could account for that:

"/\[$section\]/,/\[/{/^(\W|)$var=/p}"

That ^(\W|)$var= says "if there is whitespace at the beginning (^(\W) or nothing (|)) before your variable concatenated with an equal sign ($var=)."

If you wanted to switch over to awk you could use something like:

val=$(awk -F"=" -v section=$section -v var=$var '$1=="["section"]"{secFound=1}secFound==1 && $1==var{print $2; secFound=0}' $CONF_FILE)

That awk command splits the record by equal -F"=". Then if the first field in the record is your section ($1=="["section"]") then set variable secFound to 1. Then... if secFound is 1 and the first field is exactly equal to your var variable (secFound==1 && $1==var) then print out the second field ({print $2}) and sets secFound to 0 so we don't pick up any other Test keys.

Comments