If you have Git available and are OK with the constraint of not being able to use underscores in the key names, you can use git config as a general-purpose INI parser / editor.
It will handle parsing out the key/value pair from around the = and discard insignificant whitespace, plus you get comments (both ; and #) and type coercion basically for free. I have included a complete working example for the OP's input .ini and desired output (Bash associative arrays), below.
However, given a config file like this
; mytool.ini [section1] inputdir = ~/some/dir enablesomefeature = true enablesomeotherfeature = yes greeting = Bonjour, Monde! [section2] anothersetting = 42
…provided you just need a quick-and-dirty solution, and aren't married to the idea of having the settings in a Bash associative array, you could get away with as little as:
eval $(git config -f mytool.ini --list | tr . _) # or if 'eval' skeeves you out excessively source <(git config -f mytool.ini --list | tr . _)
which creates environment variables named sectionname_variablename in the current environment. This, of course, only works if you can trust that none of your values will ever contain a period or whitespace (see below for a more robust solution).
Other simple examples
Fetching arbitrary values, using a shell function to save typing:
function myini() { git config -f mytool.ini; }
An alias would be OK, here, too, but those are not normally expanded in a shell script [1], and anyway aliases are superseded by shell functions "for almost every purpose," [2], according to the Bash man page.
myini --list # result: # section1.inputdir=~/some/dir # section1.enablesomefeature=true # section1.enablesomeotherfeature=yes # section2.anothersetting=42 myini --get section1.inputdir # result: # ~/some/dir
With the --type option, you can "canonicalize" specific settings as integers, booleans, or paths (automatically expanding ~):
myini --get --type=path section1.inputdir # value '~/some/dir' # result: # /home/myuser/some/dir myini --get --type=bool section1.enablesomeotherfeature # value 'yes' # result: # true
Slightly more robust quick-and-dirty example
Make all variables in mytool.ini available as SECTIONNAME_VARIABLENAME in the current environment, preserving internal whitespace in key values:
source <( git config -f mytool.ini --list \ | sed 's/\([^.]*\)\.\(.*\)=\(.*\)/\U\1_\2\E="\3"/' )
What the sed expression is doing, in English, is
- finding a bunch of non-period characters up to a period, remembering that as
\1, then - finding a bunch of characters up to an equals sign, remembering that as
\2, and - finding all the characters after the equals sign as
\3 - finally, in the replacement string
- the section name + variable name is upper-cased, and
- the value part is double-quoted, in case it contains characters that have special meaning to the shell if unquoted (like whitespace)
The \U and \E sequences in the replacement string (which upper-case that part of the replacement string) are GNU sed extension. On macOS and BSD, you'd just use multiple -e expressions to achieve the same effect.
Dealing with embedded quotes and whitespace in the section names (which git config allows) is left as an exercise for the reader. :)
Using section names as keys into a Bash associative array
Given:
; foo.ini [foobar] session=foo path=/some/path [barfoo] session=bar path=/some/path
This will produce the result the OP is asking for, simply by rearranging some of the captures in the sed replacement expression, and will work fine without GNU sed:
source <( git config -f foo.ini --list \ | sed 's/\([^.]*\)\.\(.*\)=\(.*\)/declare -A \2["\1"]="\3"/' )
I predict there could be some challenges with quoting for a real-world .ini file, but it works for the provided example. Result:
declare -p {session,path} # result: # declare -A session=([barfoo]="bar" [foobar]="foo" ) # declare -A path=([barfoo]="/some/path" [foobar]="/some/path" )
iniparser inbash.