Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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?

share|improve this question
    
If there's other efficient way to do this, feel free to post your solution too :) –  Flint Jan 1 '12 at 9:24

4 Answers 4

up vote 2 down vote accepted

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.

awk -F ' *= *' '{ if ($1 ~ /^\[/) section=$1; else if ($1 !~ /^$/) print $1 section "=" "\"" $2 "\"" }'

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, using declare which is safe from most malicious content.

foobar=1
barfoo=2  # or you could increment an index variable each time a section is found
while IFS='= ' read var val
do
    if [[ $var == \[*] ]]
    then
        section=$var
    elif [[ $val ]]
    then
        declare "$var$section=$val"
    fi
done < filename

Again, associative arrays could fairly easily be supported.

share|improve this answer
1  
Very nice info and I particularly like the second technique since it uses bash built in function, instead of relying on external command. –  Flint Jan 2 '12 at 2:07

If you want to eliminate the extra spaces, you can use the built-in function gsub. For example, you can add:

gsub(/ /, "", $1);

This will remove all spaces. If you want to remove spaces at the beginning or end of token, you can use

gsub(/^ /, "", $1);
gsub(/ $/, "", $1);
share|improve this answer
    
Cool tricks. Didn't know there's such a built-in function :) –  Flint Jan 2 '12 at 1:34

I would use simple python script for this job since it has built in INI parser:

#!/usr/bin/env python

import sys, ConfigParser

config = ConfigParser.ConfigParser()
config.readfp(sys.stdin)

for sec in config.sections():
    for key, val in config.items(sec):
        print '%s[%s]="%s"' % (sec, key, val)

and then in bash:

#!/bin/bash

# load the in.ini INI file to current BASH
eval $(cat in.ini  | ./ini2arr.py)

# test it:
echo ${barfoo[session]}

Sure, there are shorter implementations in awk, but I think this is more readable and easier to maintain.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.