12

I am looking for a shell script analog to something like Pythons's ConfigParser or Perl's Config::INI. I have sourced files in the past to accomplish this, but I'd prefer to read rather than execute my "config file". Does anyone know of anything comparable to the above modules available for shell (or bash) scripts?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
zenzic
  • 1,517
  • 2
  • 16
  • 25
  • 1
    possible duplicate of [How do I grab an INI value within a shell script?](http://stackoverflow.com/questions/6318809/how-do-i-grab-an-ini-value-within-a-shell-script) – kenorb Mar 01 '15 at 15:24

5 Answers5

13

You don't want source it, so you should:

1.read the config, 2.verify lines 3.eval them

CONFIGFILE="/path/to/config"
echo "=$ADMIN= =$TODO= =$FILE=" #these variables are not defined here
eval $(sed '/:/!d;/^ *#/d;s/:/ /;' < "$CONFIGFILE" | while read -r key val
do
    #verify here
    #...
    str="$key='$val'"
    echo "$str"
done)
echo =$ADMIN= =$TODO= =$FILE= #here are defined

sample of config file

ADMIN: root
TODO: delete

var=badly_formtatted_line_without_colon

#comment
FILE: /path/to/file

if you run the above sample should get (not tested):

== == ==
=root= =delete= =/path/to/file=

sure this is not the best solution - maybe someone post a nicer one.

clt60
  • 62,119
  • 17
  • 107
  • 194
  • I guess I was thinking of something prepackaged like ConfigParser, but this certainly works. Thanks! – zenzic May 12 '11 at 21:50
  • To handle blank lines in config file: `eval $(sed '/^ *#/d;s/:/ /;' < "$CONFIGFILE" | while read key val do if [ -n "${key}" ]; then str="$key='$val'" echo "$str" fi done)` – slonik Jul 17 '14 at 08:47
  • @slonik Good point for handling blank lines. In the script the `sed` filters out unwanted lines, so enough add to sed another command, such: `/^ *$/d` (e.g. delete lines what contains only any number of spaces - e.g. zero or more). Thank you pointing me to the problem. Edited my answer. – clt60 Jul 17 '14 at 09:16
  • @slonik in fact, added a command to remove ANY line what doesn't contains a colon `:`, because it is essential. – clt60 Jul 17 '14 at 09:28
5

You might want to take a look at cfget which can be installed with sudo apt-get install cfget.

user3385188
  • 71
  • 1
  • 3
3
#!/bin/bash 
# Author: CJ
# Date..: 01/03/2013

## sample INI file save below to a file, replace "^I" with tab
#^I [    SECTION ONE     ]  
#TOKEN_TWO^I ="Value1 two   "
#TOKEN_ONE=Value1 One
#TOKEN_THREE=^I"Value1^I three" # a comment string
#TOKEN_FOUR^I=^I"^IValue1 four"
#
#[SECTION_TWO]  
#TOKEN_ONE=Value1 One ^I^I^I# another comment string
#TOKEN_TWO^I ="Value1 two   "
#TOKEN_THREE=^I"Value1^I three"
#TOKEN_FOUR^I=^I"^IValue1 four"
## sample INI file

export INI= # allows access to the parsed INI values in toto by children
iniParse() {
    # Make word separator Linefeed(\n)
    OIFS="${IFS}"
    IFS=$(echo)

    SECTION=_
    while read LINE; do {
        IFS="${OIFS}"

        # Skip blank lines
        TMP="$(echo "${LINE}"|sed -e "s/^[ \t]*//")"
        if [ 0 -ne ${#TMP} ]; then
            # Ignore comment lines
            if [ '#' == "${LINE:0:1}" -o '*' == "${LINE:0:1}" ]; then
                continue
            fi # if [ '#' == "${LINE:0:1}" -o '*' == "${LINE:0:1}" ]; then

            # Section label
            if [ "[" == "${LINE:0:1}" ]; then
                LINE="${LINE/[/}"
                LINE="${LINE/]/}"
                LINE="${LINE/ /_}"
                SECTION=$(echo "${LINE}")_
            else
                LINE="$(echo "${LINE}"|sed -e "s/^[ \t]*//")"
                LINE="$(echo "${LINE}"|cut -d# -f1)"

                TOKEN="$(echo "${LINE:0}"|cut -d= -f1)"
                EQOFS=${#TOKEN}
                TOKEN="$(echo "${TOKEN}"|sed -e "s/[ \t]*//g")"

                VALUE="${LINE:${EQOFS}}"
                VALUE="$(echo "${VALUE}"|sed -e "s/^[ \t=]*//")"
                VALUE="$(echo "${VALUE}"|sed -e "s/[ \t]*$//")"

                if [ "${VALUE:0:1}" == '"' ]; then
                    echo -n "${SECTION}${TOKEN}=${VALUE}"
                    echo -e "\r"
                else
                    echo -n "${SECTION}${TOKEN}="\"${VALUE}\"""
                    echo -e "\r"
                fi # if [ "${VALUE:0:1}" == '"' ]; then
            fi # if [ "[" == "${LINE:0:1}" ]; then 
        fi # if [ 0 -ne ${#TMP} ]; then

        IFS=$(echo)
    } done <<< "$1"

    IFS="${OIFS}" # restore original IFS value
} # iniParse()

# call this function with the INI filespec
iniReader() {
    if [ -z "$1" ]; then return 1; fi

    TMPINI="$(<$1)"
    TMPINI="$(echo "${TMPINI}"|sed -e "s/\r//g")"
    TMPINI="$(echo "${TMPINI}"|sed -e "s/[ \t]*\[[ \t]*/[/g")"
    TMPINI="$(echo "${TMPINI}"|sed -e "s/[ \t]*\][ \t]*/]/g")"

    INI=`iniParse "${TMPINI}"`
    INI="$(echo "${INI}"|sed -e "s/\r/\n/g")"
    eval "${INI}"

    return 0
} # iniReader() {

# sample usage
if iniReader $1 ; then
    echo INI read, exit_code $? # exit_code == 0
    cat <<< "${INI}"
    cat <<< "${SECTION_ONE_TOKEN_FOUR}"
    cat <<< "${SECTION_ONE_TOKEN_THREE}"
    cat <<< "${SECTION_TWO_TOKEN_TWO}"
    cat <<< "${SECTION_TWO_TOKEN_ONE}"
else
    echo usage: $0 filename.ini
fi # if iniReader $1 ; then
0

grep based alternative seems to be more readable:

CONFIG_FILE='/your/config/file.ini'
eval $(grep '^\[\|^#' CONFIG_FILE -v | while read line
  do echo $line
done)

Where:

  • -v grep option means exclude matching lines
  • ^\[\|^# selects all lines which starts with [ or # (configparser sections and comments)

It will work ONLY if your config file doesn't have spaces around = (if you would like to generate config with Python use space_around_delimiters=False see https://docs.python.org/3/library/configparser.html#configparser.ConfigParser.write)

Supported config example:

FIRST_VAR="a"

[lines started with [ will be ignored]
secondvar="b"

# some comment
anotherVar="c"
jmarceli
  • 19,102
  • 6
  • 69
  • 67
-1

You can use bash it-self to interpret ini values, by:

$ source <(grep = file.ini)

Sample file:

[section-a]
  var1=value1
  var2=value2

See more examples: How do I grab an INI value within a shell script?

Or you can use bash ini-parser which can be found at The Old School DevOps blog site.

Community
  • 1
  • 1
kenorb
  • 155,785
  • 88
  • 678
  • 743