How can I parse an ini file whose values may contain certain characters? Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of How can I parse an ini file whose values may contain certain characters? without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I have looked at a couple bash ini parsing scripts and I’ve seen this one used a few times here so I’m trying to see if it will work for me. It looks like it reads the ini file line by line multiple times and with each pass it progressively constructs a function that finally gets eval’d. It works fine for some special characters but not others. If a value in the file contains a single quote or greater/less than symbol, the script returns syntax errors. Other symbols create unexpected results as well. How can I handle these characters as the are encountered?

This is the function that parses the ini.

#!/usr/bin/env bash
cfg_parser ()
{
    ini="$(<$1)"                # read the file
    ini="${ini//[/[}"          # escape [
    ini="${ini//]/]}"          # escape ]
    IFS=$'n' && ini=( ${ini} ) # convert to line-array
    ini=( ${ini[*]//;*/} )      # remove comments with ;
    ini=( ${ini[*]/    =/=} )  # remove tabs before =
    ini=( ${ini[*]/=   /=} )   # remove tabs be =
    ini=( ${ini[*]/ = /=} )   # remove anything with a space around =
    ini=( ${ini[*]/#\[/}$'n'cfg.section.} ) # set section prefix
    ini=( ${ini[*]/%\]/ (} )    # convert text2function (1)
    ini=( ${ini[*]/=/=( } )    # convert item to array
    ini=( ${ini[*]/%/ )} )     # close array parenthesis
    ini=( ${ini[*]/%\ )/ \} ) # the multiline trick
    ini=( ${ini[*]/%( )/() {} ) # convert text2function (2)
    ini=( ${ini[*]/%} )/}} ) # remove extra parenthesis
    ini[0]="" # remove first element
    ini[${#ini[*]} + 1]='}'    # add the last brace
    eval "$(echo "${ini[*]}")" # eval the result
}

ini file

[Section1]
value1=abc`def # unexpected EOF while looking for matching ``'
value2=ghi>jkl # syntax error near unexpected token `>'
value3=mno$pqr # executes ok but outputs "mnoqr"
value4=stu;vwx # executes ok but outputs "stu"

Answer

The fact that you can do something in bash doesn’t mean that you should.

sh (and bash etc) scripts are best suited to be relatively simple wrappers to launch programs or around text-processing commands. For more complicated tasks, including parsing ini files and acting on them, other languages are more appropriate. Have you considered writing your script in perl or python? Both have good .ini file parsers – I’ve used perl’s Config::INI module several times when I’ve needed to parse an ini file.

But if you insist on doing it in bash, you should use an associative array instead of setting individual variables.

Start with something like this:

#! /bin/bash

inifile='user1074170.ini' 

# declare $config to be an associative array
declare -A config

while IFS='=' read -r key val ; do 
    config["$key"]="$val"
done <  <(sed -E -e '/^[/d
                     s/#.*//
                     s/[[:blank:]]+$|^[[:blank:]]+//g' "$inifile" )

# now print out the config array
set | grep '^config='

The sed script deletes the [Section1] line (actually, all lines beginning with an open-square-bracket [ – you will want to handle this differently[1] in an ini file with multiple sections), and removes comments as well as leading and trailing blanks. The while loop reads in each line, using = as a field delimiter, and assigns the contents to variables $key and $val, which are then added to the $config array.

Output:

config=([value1]="abc`def" [value3]="mno$pqr" [value2]="ghi>jkl" [value4]="stu;vwx" )

You can use the array entries later in your script like this:

$ echo value1 is "${config[value1]}"
value1 is abc`def

$ [ "${config[value4]}" = 'stu;vwx' ] && echo true
true

[1] awk or perl have conveniently easy ways of reading files in “paragraph” mode. A paragraph being defined as a block of text separated from other text blocks by one or more blank lines.

e.g. to work with only [Section1], insert the awk script below immediately before the sed script feeding into the while loop above:

awk -v RS= -v ORS='nn' '/[Section1]/' "$inifile" | sed ...

(and remove "$inifile" from the end of the sed command line, of course – you don’t want to feed the file in again after you’ve gone to the trouble of extracting only [Section1] from it).

Setting ORS isn’t strictly necessary if you’re only extracting one section from the ini file – but will be useful to maintain paragraph separation if you’re extracting two or more sections.

We are here to answer your question about How can I parse an ini file whose values may contain certain characters? - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji