While playing with my home network I was presented with a curios problem - parsing .ini file within bash.
Let's take the following file as an example:
[Alfa]
IP=1.1.1.1
DNS=alfa.example.com
[Bravo]
IP=2.2.2.2
DNS=bravo.example.com
[Charlie]
IP=3.3.3.3
DNS=charlie.example.com
From this file I want to get both IP and DNS fields of one section - e.g. Bravo
. I did find a solution that was rather close to what I wanted but I didn't like the fact all entries got into associative array.
So I decided to make a similar solution adjusting the output to show only a single section and give it a prefix to avoid accidental conflict with other script variables. Here is the one-liner I came up with:
awk -v TARGET=Bravo -F ' *= *' '{ if ($0 ~ /^\[.*\]$/) { gsub(/^\[|\]$/, "", $0); SECTION=$0 } else if (($2 != "") && (SECTION==TARGET)) { print "FIELD_" $1 "=\"" $2 "\"" }}' My.ini
Or to present it in more human-friendly form:
awk -v TARGET=Bravo -F ' *= *' '
{
if ($0 ~ /^\[.*\]$/) {
gsub(/^\[|\]$/, "", $0)
SECTION=$0
} else if (($2 != "") && (SECTION==TARGET)) {
print "FIELD_" $1 "=\"" $2 "\""
}
}
' My.ini
The first argument (-v TARGET=Bravo
) just specifies which section we're searching. I am keeping it outside as that way I can use other variable (e.g. $MACHINE
) without dealing with escaping awk statements.
The second argument (-F ' *= *'
) is actually regex ensuring there are no spaces around equals sign.
The third argument is what makes it all happen. Code matches section line and puts it in SECTION
variable. Each line with name/value pair is further checked and printed if target section name is matched. Upon printing, a prefix "FIELD_
" is added before name making the whole line essentially a variable declaration.
The fourth and last argument is simply a file name.
This particular command example will output the following text:
FIELD_IP="2.2.2.2"
FIELD_DNS="bravo.example.com"
How do you use it in a script? Simple source result of awk
and you get to use .ini fields as any bash variable.
source <( awk… )