ajdiaz
-
07:42:07 pm on February 9, 2008 | # |
In some situations i like to use INI files as configuration files, as python do. But bash do not provide a parser for these files, obviously you can use a awk code or a couple of sed calls, but if you are bash-priest and do not want to use nothing more, then you can try the following obscure code:
cfg.parser () { IFS=$'\n' && ini=( $(<$1) ) # convert to line-array ini=( ${ini[*]//;*/} ) # remove comments 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[*]/%\( \)/\(\) \{} ) # 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 }And then you can parse your ini files as following:
# parse the config file called 'myfile.ini', with the following # contents:: # [sec2] # var2='something' cfg.parser 'myfile.ini' # enable section called 'sec2' (in the file [sec2]) for reading cfg.section.sec2 # read the content of the variable called 'var2' (in the file # var2=XXX). If your var2 is an array, then you can use # ${var[index]} echo "$var2"Unfortunately, the cfg.parser() function do no support embedded spaces
in section names… yet
Shawn 5:27 pm on 18 February 2008 | # |
Uh-oh:
eval: line 2: syntax error near unexpected token `}’
eval: line 2: `}’
Hopefully this is just a typo in the code above as I’d be super happy to get this to work and I’m just not quite good enough to figure out what is wrong.
Thanks for posting this!
ajdiaz 6:22 pm on 18 February 2008 | # |
Mmm, the code works for me
There are my ‘myfile.ini’:
[~]$ cat myfile.ini
[sec2]
var2=XXX
And the result:
[~]$ ./ini.sh
XXX
Maybe you need bash >= 3.0?, I’m using:
[~]$ echo ${BASH_VERSION}
3.2.17(1)-release
If you want, send me the result of the command:
$ bash -x ini.sh
And I try to help you
Thanks for your comments!!
Greg 1:58 pm on 3 March 2008 | # |
This script also doesn’t work if the ini file is not fully standard, like samba’s smb.conf. In that, there are some white spaces on both sides of the equation sign.
ajdiaz 10:50 pm on 8 March 2008 | # |
Sure, the script do not work fine with non stardard files, becaus the script parse file variables as bash variables and spaces are not allowed in bash variables. But, you are free to replace spaces with another character.
Tomas 2:24 pm on 29 April 2008 | # |
This works great!
Do you have any functionality for updating the functions array dynamically without re-parsing the ini-file?
Example: Add new section or add/update field within a section.
I’m considering trying to code this, but it would of course save me lots of time if it already exists
ajdiaz 3:34 pm on 1 May 2008 | # |
Sorry, I don’t code any functions to update the array. Really this hack do not use an array. We read the ini and create a couple of variables with the same name as variable in the file, and change the section creating a function called the section name. So if you need to add a new section, you might do:
cfg.section.MYNEWSECTION ()
{
MYNEWVAR1=”MYNEWVALUE1″
# any other variable
}
Now I’m working in a dump function to write the ini from specified functions.
Emanuele 3:16 pm on 8 May 2008 | # |
Hi,
I’ve only copy the function in my bash script and I receive the following error:
‘cfg.parser’:not a valid identifier
someone know why?
BASH_VERSION -> 3.1.17(1)
ajdiaz 5:04 pm on 10 May 2008 | # |
Yes, probably your bash is running with POSIX option (check the value of $HELLOPTS), in this case the dot (.) is not a valid character for function name.
If you really require a POSIX shell compatibility, you can replace cfg.parser and cfg.sections by cfg_parser and cfg_sections, the underline is always a valid character
Emanuele 10:00 am on 12 May 2008 | # |
Thanks! now I try!
Henning 2:37 pm on 20 June 2008 | # |
The source listing is somehow garbled. There’s something wrong with quotes (backticks?). The show up as a single character (” resp. “=
ajdiaz 2:48 pm on 20 June 2008 | # |
Sure, the wordpress format is not very readable with selected theme, use the pastebin code in http://pastebin.com/f61ef4979 instead
Stephen 10:13 pm on 27 June 2008 | # |
The following will parse out a file that has spaces between the ‘=’ as well as both ; and # comments. Just thought I would share it.
function cfg.parser ()
{
IFS=$’\n’ && ini=( $(<$1) ) # convert to line-array
ini=( ${ini[*]//;*/} ) # remove comments ‘;’
ini=( ${ini[*]//\#*/} ) # remove comments ‘#’
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[*]/%\( \)/\(\) \{} ) # convert text2function (2)
ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis
ini=( ${ini[*]/#\ */} ) # remove blank lines
ini=( ${ini[*]/#\ */} ) # remove blank lines with tabs
ini[0]=” # remove first element
ini[${#ini[*]} + 1]=’}’ # add the last brace
#printf “%s\n” ${ini[*]}
eval “$(echo “${ini[*]}”)” # eval the result
}
Lars 7:31 pm on 1 September 2008 | # |
Thanks for your script!
Is there any chance to get the available variables of a section?
For example: if I know that there’s a section [sec2], how can I print out the content of this section?
I think I need something like this:
for var in cfg.section.sec2; do
print “variable: %s\n” $var;
print “value: %s\n” $var[*];
done
but that doesn’t work for me.
ajdiaz 1:01 pm on 2 September 2008 | # |
declare -f cfg.section.sec2 | grep ‘=’ must be work Lars
frank 9:31 pm on 16 October 2008 | # |
Just a quick question… At one point I had this working, however, now all but the first section has been replaced by the number ‘1′. It’s replace right after this line:
IFS=$’\n’ && ini=( $(<$1) )
I’m using bash 3.0. Any thoughts?
Thanks for the help.
Three of Coins » Blog Archive » Bash .ini file parser 2:30 pm on 11 November 2008 | # |
[...] found on the Net a cute little bash parser for .ini files. Since I do runtime configuration for CL-Trane based projects in an ini file, parsed with [...]
Maciej Pasternacki 11:02 pm on 19 November 2008 | # |
One more fix: script changes $IFS and doesn’t restore previous value. Took me quote a moment of debugging, why the hell after reading config word splitting doesn’t work as they used to (e.g. LS=”ls -a”;$LS doesn’t work, because bash tries to find and execute “ls -a” command, including space and parameter). Fixed version:
function cfg.parser ()
{
_old_IFS=”$IFS” # save $IFS
IFS=$’\n’ && ini=( $(<$1) ) # convert to line-array
ini=( ${ini[*]//;*/} ) # remove comments `;’
ini=( ${ini[*]//\#*/} ) # remove comments `#’
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[*]/%\( \)/\(\) \{} ) # convert text2function (2)
ini=( ${ini[*]/%\} \)/\}} ) # remove extra parenthesis
ini=( ${ini[*]/#\ */} ) # remove blank lines
ini=( ${ini[*]/#\ */} ) # remove blank lines with tabs
ini[0]=” # remove first element
ini[${#ini[*]} + 1]=’}’ # add the last brace
# printf “%s\n” ${ini[*]}
eval “$(echo “${ini[*]}”)” # eval the result
if [ -z "$_old_IFS" ] # restore old $IFS
then unset IFS
else IFS=”$_old_IFS”
fi
}
Brooks Moses 12:59 am on 16 January 2009 | # |
Maceij: Why not just use “local IFS” at the top of the function?
Piotr Gabryjeluk 12:57 pm on 23 February 2009 | # |
Yeah, should be
local IFS instead of just IFS
the rest of the script seemed a bit magic to me at first, but anyway nice peace of work. (I would suggest not using a dot in name of function).
Markus E. 1:34 pm on 7 May 2009 | # |
nice work!
the error described in first post occurs if a section does not contain values.
this can be solved by adding any command between the brackets which are evaluated by eval().
i think, there could be a better solution, but following works;
replace:
ni[${#ini[*]} + 1]=’}’ # add the last brace
with something like:
ini[${#ini[*]} + 1]=’echo -n; }’
neofutur 5:17 am on 20 May 2009 | # |
useful post, but the wordpress format makes it a hell to use it.
what about packaging this in a .tar.gz and give the download link ?
ajdiaz 5:14 pm on 21 May 2009 | # |
My original code, is also uploaded in pastebin: http://pastebin.com/f61ef4979
Feel free to add modifications
bld 2:56 pm on 21 May 2009 | # |
This Bash ini parser may be easier to cut & paste:
http://codesnippets.joyent.com/posts/show/2060
cheers,
bld
nic 11:04 pm on 17 August 2009 | # |
Hello!
I tried the wonderful script and I’m even starting to understand what it does. I would like to modify the two areas where the text is converted to function and key names to do this: uppercase the names and in the case of the section name replace blank characters with underscore. I don’t know how to do this, especially since the script runs the regex for the whole file in one swing (IE not line by line).
Best regards
ajdiaz 8:11 pm on 19 August 2009 | # |
Hi!
To put the ini contents in uppercase is easy, just change the line:
IFS=$'\n' && ini=( $(<$1) )by the line:
IFS=$'\n' && ini=( $(tr a-z A-Z <$1) )This will be work ok to you. About the spaces in sections, there are no a easy way to do this AFAIK.
I hope to help you a bit.
Regards,
Andres