I'm trying to convert an ini file into bash array variables. The sample ini is as below:
[foobar]
session=foo
path=/some/path
[barfoo]
session=bar
path=/some/path
so these become:
session[foobar]=foo
path[foobar]=/some/path
session[barfoo]=bar
and so on.
Right now, I could come up with only this command
awk -F'=' '{ if ($1 ~ /^\[/) section=$1; else if ($1 !~ /^$/) print $1 section "=" $2 }'
Also, another problem is, it doesn't take spaces near =
into consideration. I think sed
is probably better suited for this job but I don't know how to hold and store a temporary variable for the section name in sed
.
So any idea how to do this?
Gawk accepts regular expressions as field delimiters. The following eliminates spaces around the equal sign, but preserves them in the rest of the line. Quotes are added around the value so those spaces, if any, are preserved when the Bash assignment is performed. I'm assuming that the section names will be numeric variables, but if you're using Bash 4, it would be easy to adapt this to use associative arrays with the section names themselves as the indices.
Note that you may want to also do the space removal that Khaled shows (on only $1 and section) since Bash variable names can't contain spaces.
Also, this method won't work if the values contain equal signs.
Another technique would be to use a Bash
while read
loop and perform the assignments as the file is read, usingdeclare
which is safe from most malicious content.Again, associative arrays could fairly easily be supported.
I would use simple python script for this job since it has built in INI parser:
and then in bash:
Sure, there are shorter implementations in awk, but I think this is more readable and easier to maintain.
If you want to eliminate the extra spaces, you can use the built-in function
gsub
. For example, you can add:This will remove all spaces. If you want to remove spaces at the beginning or end of token, you can use
Here's a pure bash solution.
This is a new and improved version of what chilladx posted:
https://github.com/albfan/bash-ini-parser
For a really easy to follow initial example: After you download this, just copy the files
bash-ini-parser
, andscripts/file.ini
to the same directory, then create a client test script using the example I've provided below to that same directory as well.Here are some further improvements I made to the bash-ini-parser script...
If you want to be able to read ini files with Windows line endings as well as Unix, add this line to the cfg_parser function immediately following the one which reads the file:
If you want to read files which have restrictive access permissions, add this optional function:
Always assuming to have Python's ConfigParser around, one may build a shell helper function like this:
$IFACE
and$param
are the section respectively the parameter.This helper then allows calls like:
Hope this helps!
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
…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:
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:
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.
With the
--type
option, you can "canonicalize" specific settings as integers, booleans, or paths (automatically expanding~
):Slightly more robust quick-and-dirty example
Make all variables in
mytool.ini
available asSECTIONNAME_VARIABLENAME
in the current environment, preserving internal whitespace in key values:What the sed expression is doing, in English, is
\1
, then\2
, and\3
The
\U
and\E
sequences in the replacement string (which upper-case that part of the replacement string) are GNUsed
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:
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:
I predict there could be some challenges with quoting for a real-world
.ini
file, but it works for the provided example. Result:With a lot of help from the answers in this post, as well as other on this site and some foogle (not a typo), I have come up with the following "solution" quoted because of the caveat at the end. I would prefer a pure bash method but everything I have seen either does not seem to work with my bash version or is rather cumbersome.
This fits the final category but still is less cumbersome than other options.
filename: functions
filename: options.ini
filename: options This is the file that calls the function. so functions needs to be sourced here.
And finally to access you need to source options:
filename: someapplication
I have looked at other options to "automatically" generate the variable by parsing the whole INI file but I am not sure there is anything really simple.
With this way, you can update the variables as you need to add them to your ini file. But, the caveat being it's not scalable in any meaningful way yet.