Reading a Config File in a Bash Script

3 minute read Published: 2022-04-25

Today I was looking into how to add a configuration file to a script.

And this how I implemented it:

parse_ini()
{
    cat <<EOF | python3
from configparser import ConfigParser

config = ConfigParser()
config.read("$1")

for section in config.sections():
    print(f'declare -A {section}')
    for key, value in config.items(section):
        print(f'{section}[{key}]="{value}"')
EOF
}

The parse_ini use an inline Pythonscripts to parse the configuration file, then convert it to a bash script that is printed on the standard output.

Each section is translated to an associative array (an associative array variable in bash is similar to a dictionary in Python).

So if you have this config file, named config.ini:

[CONFIG]
MY_KEY="Hello"

You can access to the value of MY_KEY in bash with:

source <(parse_ini config.ini)
echo ${CONFIG[my_key]}
> Hello

Advanced example

This example demonstrate how you can use a variable to select from which section you want to get the value from a key.

We will create a translatable hello-world script:

First we create a hello-world-translation.ini file with:

[FR]
HELLO_WORLD=Bonjour le monde

[EN]
HELLO_WORLD=Hello World

Then we create the hello-world.sh scripts as follows

#!/usr/bin/env bash

# This script just echo "Hello World" in the terminal, but
# you can change the language by settings the first parameter the `FR`

# In order to it to work, we need to create a name reference with declare -n
declare -n LANG=${1:-EN} # Use english by default

# Note: using normal

parse_ini()
{
    cat <<EOF | python3
from configparser import ConfigParser

config = ConfigParser()
config.read("$1")

for section in config.sections():
    print(f'declare -A {section}')
    for key, value in config.items(section):
        print(f'{section}[{key}]="{value}"')
EOF
}

source <(parse_ini hello-world-translation.ini)

echo ${LANG[hello_world]}

And finally, use it from the console:

chmod +x hello-world.sh
./hello-world.sh
> Hello World

./hello-world.sh FR
> Bonjour le monde

./hello-world.sh EN
> Hello World

Of course, you can call multiple time the parse_ini function to read from multiple file. Section will be merged together and value overwritten.

Source and useful links

The solution is heavily inspired from this serverfault entry

You can also learn how to use an associative array or what is a nameref variable

Dependencies

The code require at least Bash 4.3 and should work with any Python 3 version.