Created
August 16, 2014 01:03
-
-
Save RoUS/54425ead07844daecf90 to your computer and use it in GitHub Desktop.
Bash function to read keys/values from an ini-style file section into an associative envariable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- | |
# vim: ts=4:sw=4:noet | |
# | |
function _read_config_file() { | |
local _cfgfile='/dev/stdin' | |
local _section | |
local _varname='CONFIG_HASH' | |
local _line | |
local _key | |
local _value | |
local _cursection | |
local _sectfound | |
while [ -n "$*" ]; do | |
case "$1" in | |
-h | --help) | |
cat <<EOF | |
${FUNCNAME[0]} - Bash function to read settings from an ini-file | |
Usage: | |
${FUNCNAME[0]} [OPTIONS] | |
Options: | |
-h, --help Display this text. | |
-f FILE, --file=FILE Read from specified file. | |
Default is stdin. | |
-s SECTION, --section=SECTION Name of section to process in file. | |
Default is first section encountered. | |
-v VARNAME, --variable-name=VARNAME Environment variable into which | |
settings will be loaded. Default is | |
CONFIG_HASH | |
Example: | |
Given a file named 'test.ini' with the following contents: | |
--- snip 8<--- | |
# Comment line | |
[section-1] | |
sec1key1 = sec1key1-value | |
sec1key2 = sec1key2-value | |
[section-2] | |
sec2key1 = sec2key1-value | |
sec2key2 = sec2key2-value | |
--- snip 8<--- | |
here are the results from the following commands: | |
$ ${FUNCNAME[0]} < test.ini | |
=> CONFIG_HASH=([sec1key1]='sec1key1-value',[sec1key2]='sec1key2-value') | |
$ ${FUNCNAME[0]} -s section-1 < test.ini | |
=> CONFIG_HASH=([sec1key1]='sec1key1-value',[sec1key2]='sec1key2-value') | |
$ ${FUNCNAME[0]} -s section-2 < test.ini | |
=> CONFIG_HASH=([sec2key1]='sec2key1-value',[sec2key2]='sec2key2-value') | |
$ ${FUNCNAME[0]} -s section-2 -v Derpy < test.ini | |
=> Derpy=([sec2key1]='sec2key1-value',[sec2key2]='sec2key2-value') | |
EOF | |
return 0 | |
;; | |
-f | --file | --file=*) | |
if [[ "$1" =~ --file= ]]; then | |
_cfgfile=${1#*=} | |
else | |
shift | |
_cfgfile=$1 | |
fi | |
shift | |
;; | |
-s | --section | --section=*) | |
if [[ "$1" =~ --section= ]]; then | |
_section=${1#*=} | |
else | |
shift | |
_section=$1 | |
fi | |
shift | |
;; | |
-v | --variable-name | --variable-name=*) | |
if [[ "$1" =~ --variable-name= ]]; then | |
_varname=${1#*=} | |
else | |
shift | |
_varname=$1 | |
fi | |
shift | |
;; | |
*) | |
break | |
;; | |
esac | |
done | |
typeset -p ${_varname} 2> /dev/null || declare -A ${_varname} | |
{ | |
while read _line; do | |
# | |
# Remove all leading and trailing whitespace from the line. | |
# | |
if [[ ${_line} =~ ^[[:space:]]*(.*?)[[:space:]]*$ ]]; then | |
_line=${BASH_REMATCH[1]} | |
fi | |
# | |
# If the first character of the trimmed line is a '#' it's a | |
# comment -- skip it. | |
# | |
if [[ "${_line:0:1}" == '#' ]] || [ -z "${_line}" ]; then | |
continue | |
fi | |
# | |
# See if this is a section header | |
# | |
if [[ ${_line} =~ ^\[([^][:space:]]*)\] ]]; then | |
_cursection=${BASH_REMATCH[1]} | |
# | |
# This is a section line. Here's what can happen: | |
# | |
# 1. We're not looking for a specific section, so we make | |
# *this* one our choice. | |
# 2. We *are* looking for a particular section but haven't | |
# found it, and this isn't it either. Keep looking. | |
# 3. This isn't our section, but we just finished reading | |
# ours -- so we're done. | |
# 4. This is our section -- start processing it. | |
# | |
# | |
# No section requested, so make this the one. | |
# | |
if [ -z "${_section}" ]; then | |
_section=${_cursection} | |
fi | |
# | |
# Is this the section we want? | |
# | |
if [[ "${_cursection}" == "${_section}" ]]; then | |
# | |
# Make a note that we've found it, and move on to the | |
# next line. | |
# | |
_sectfound=${_section} | |
elif [ -n "${_sectfound}" ]; then | |
# | |
# We found our section already, and this isn't it -- | |
# so we've moved past it. We're done. | |
# | |
break | |
fi | |
continue | |
fi | |
if [ -z "${_sectfound}" ]; then | |
# | |
# We're not in a position to process any settings; we | |
# need to find the right section. | |
# | |
continue | |
fi | |
# | |
# Time to start reading settings. At this point, we're | |
# in the right section, and we've already ruled out comment | |
# and blank lines. We're only interested in 'key = value' | |
# lines at the moment; we ignore anything else. | |
# | |
if [[ "${_line}" =~ ^([^[:space:]]*)[[:space:]]*= ]]; then | |
_key=${BASH_REMATCH[1]} | |
_value=${_line#${_key}*=} | |
if [[ "${_value}" =~ ^[[:space:]]*(.*?)[[:space:]]*$ ]]; then | |
_value=${BASH_REMATCH[1]} | |
fi | |
fi | |
eval "${_varname}[${_key}]=\${_value}" | |
done | |
} < "${_cfgfile}" | |
} |
[qualified] Thanks! I had a need to configure some bash stuff, and created an itch to scratch with this. :-)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
While anyone who does such things in bash is clearly destined for the Inferno, you have done this exceedingly well. I can find nothing to criticize about it except your choice of language.