Reading value from an ini style file with sed/awk
Asked Answered
F

2

6

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.

Felony answered 16/6, 2016 at 19:45 Comment(0)
E
8

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.

Extort answered 16/6, 2016 at 19:56 Comment(2)
Thanks! That works well. The only problem of this approach is that it will fail if there are spaces (or tabs) in front of the variable name. Is it possible to add something like " "* to the search string?Felony
I updated with an sed example that accounts for whitespace before the key/value pair.Extort
Z
0

I encountered this problem and came up with a solution similar to others here. The main difference is it uses a single awk call to get a response suitable for creating an associative array of the property/value pairs for a section.

This will not ignore the commented properties. Though adding something to do that should not be to hard.

Here's a testing script demonstrating the awk and declare statements used;

#!/bin/bash
#
# Parse a INI style properties file and extract property values for a given section
# 
# Author: Alan Carlyle
# License: CC0 (https://creativecommons.org/about/cclicenses/)
#
# Example Input: (example.properties)
#  [SEC1]
#  item1=value1
#  item2="value 2"
#
#  [Section 2]
#  property 1="Value 1 of 'Section 2'"
#  property 2='Single "quoted" value'
#
# Usage:  
# $ read_props example.properties "Section 2" property\ 2
# $ Single "quoted" value
#
# Section names and properties with spaces do not need to be quoted. 
# Values with spaces must be quoted. Values can use single or double quotes.
# The following characters [ = ] can not be used in names or values.
#
# If the property is not provided the the whole section is outputed.
#

propertiesFile=$1
section=$2
property=$3

# Extract the propetites for the section formated as for associtive array
sectionData="( "$(awk -F'=' -v s="$section" '/^\[/{ gsub(/[\[\]]/, "", $1); f = ($1 == s); next } 
    NF && f{ print "["$1"]="$2 }' $propertiesFile)" )"

# Create associtive array from extracted section data
declare +x -A "properties=$sectionData"

if [ -z "$property" ] 
then
  echo $sectionData
else
  echo ${properties[$property]}
fi
Zincography answered 28/8, 2022 at 14:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.