Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ The INI file format supports the following features:

Sections: [section]
Properties: name=value
Comments: ; comment
Comments: ; comment
# comment

Blank lines and trailing writespace are ignored as is whitespace around
the '=' - ie.
Blank lines and trailing writespace are ignored as is whitespace around
the '=' - ie.

name = value

is equivalent to
is equivalent to

name=value

Whitespace and quotes within a value are preserved (though values don't
in general need to be quoted and will not be subject to shell parameter
Whitespace and quotes within a value are preserved (though values don't
in general need to be quoted and will not be subject to shell parameter
splitting)

Values can be continuted onto subsequent lines if these are prefixed with
Expand All @@ -30,7 +30,7 @@ whitespace - ie.
name=line1
line2

is equivalent to:
is equivalent to:

name = line1 line2

Expand All @@ -39,7 +39,7 @@ keys in the format "<section>.<name>" (properties without an associated
section are stored as ".<name>". In most cases this is transparent as the
list/get commands can be used to query the data

The functionality is more or less equivalent to the Python ConfigParser
The functionality is more or less equivalent to the Python ConfigParser
module with the following exceptions

- Properties are allowed outside sections
Expand Down Expand Up @@ -70,6 +70,10 @@ section1.abc
section1.ghi
section2.xyz

$ listKeys section1
section1.abc
section1.ghi

$ listAll
.global a global value
section1.abc def
Expand All @@ -80,6 +84,10 @@ $ listSection section1
section1.abc def
section1.ghi jkl

$listSection
section1
section2

$ getProperty global
a global value

Expand All @@ -99,34 +107,32 @@ parseIniFile < file

Parse ini file (reads from stdin) and saves data to global _CONFIG var

listKeys
listKeys <section=none>

List keys present in config file in format "<section>.<property>"

listAll

List keys and data in format "<section>.<property> <value>"

listSection <section>
listSection <section=none>

List keys and data for given section (sepcified as $1) in format
"<property> <value>"
"<property> <value>",if will list all sections when section parameter empty

getProperty [name|section.name]

Print value for given property (sepcified as $1)
Print value for given property (sepcified as $1)
Properties without a section can be queried directly as
"name" (rather than ".name")

Returns 0 (true) if property found otherwise 1 (false)

getPropertyVar <variable> [name|section.name]

Save value for given property (sepcified as $2)
Save value for given property (sepcified as $2)
into shell variable (specified as $1)
Properties without a section can be queried directly as
"name" (rather than ".name")

Returns 0 (true) if property found otherwise 1 (false)


91 changes: 56 additions & 35 deletions ini_parser.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@
# ------------
#
# Functions for parsing INI-style file natively in bash.
#
#
# The INI file format supports the following features:
#
# Sections: [section]
# Properties: name=value
# Comments: ; comment
# Comments: ; comment
# # comment
#
# Blank lines and trailing writespace are ignored as is whitespace around
# the '=' - ie.
#
# Blank lines and trailing writespace are ignored as is whitespace around
# the '=' - ie.
#
# name = value
#
# is equivalent to
#
#
# is equivalent to
#
# name=value
#
# Whitespace and quotes within a value are preserved (though values don't
# in general need to be quoted and will not be subject to shell parameter
# Whitespace and quotes within a value are preserved (though values don't
# in general need to be quoted and will not be subject to shell parameter
# splitting)
#
# Values can be continuted onto subsequent lines if these are prefixed with
Expand All @@ -31,18 +31,18 @@
# name=line1
# line2
#
# is equivalent to:
#
# is equivalent to:
#
# name = line1 line2
#
# Properties are stored in the global _CONFIG array as ( k1 v1 k2 v2 ... ) with
# keys in the format "<section>.<name>" (properties without an associated
# section are stored as ".<name>". In most cases this is transparent as the
# list/get commands can be used to query the data
#
# The functionality is more or less equivalent to the Python ConfigParser
# The functionality is more or less equivalent to the Python ConfigParser
# module with the following exceptions
#
#
# - Properties are allowed outside sections
# - Multi-line properties are joined with ' ' rather than '\n' (due to shell
# quoting issues)
Expand All @@ -51,7 +51,7 @@
# -----
#
# Given the following ini file (test.ini) -
#
#
# ; A test ini file
# global = a global value
# [section1]
Expand All @@ -60,7 +60,7 @@
# [section2]
# xyz = abc ; extends over two lines
# def
#
#
# Parse config file -
#
# $ parseIniFile < test/t2.ini
Expand All @@ -71,12 +71,20 @@
# section1.ghi
# section2.xyz
#
# $ listKeys section1
# section1.abc
# section1.ghi
#
# $ listAll
# .global a global value
# section1.abc def
# section1.ghi jkl
# section2.xyz abc def
#
# $ listSection
# section1
# section2
#
# $ listSection section1
# section1.abc def
# section1.ghi jkl
Expand All @@ -97,6 +105,7 @@
shopt -s extglob

_CONFIG=()
_SECTION=()

# Commands
# --------
Expand All @@ -115,7 +124,7 @@ function parseIniFile() {

local IFS=""

while read LINE
while read LINE
do
LINE=${LINE%%[;#]*} # Strip comments
LINE=${LINE%%*( )} # Strip trailing whitespace
Expand All @@ -134,9 +143,10 @@ function parseIniFile() {
if [[ $LINE =~ ^\[([[:alnum:]]+)\] ]] # Section
then
SECTION=${BASH_REMATCH[1]}
_SECTION=(${_SECTION[@]} "${SECTION}")
KEY=""
elif [[ $LINE =~ ^([^[:space:]]+)[[:space:]]*=[[:space:]]*(.+) ]] # Property
then
then
KEY=${BASH_REMATCH[1]}
VALUE="${BASH_REMATCH[2]}"
fi
Expand All @@ -156,9 +166,13 @@ function parseIniFile() {

function listKeys() {
local -i i
local SECTION=$1
for ((i=0; i<${#_CONFIG[@]}; i+=2))
do
echo ${_CONFIG[i]}
if [[ -z ${SECTION} ]] || [[ ${_CONFIG[$i]} =~ ^${SECTION}\.(.+) ]]
then
echo ${_CONFIG[i]}
fi
done
}

Expand All @@ -184,18 +198,26 @@ function listAll() {
function listSection() {
local -i i
local SECTION=$1
for ((i=0; i<${#_CONFIG[@]}; i+=2))
do
if [[ ${_CONFIG[$i]} =~ ^${SECTION}\.(.+) ]]
then
echo ${_CONFIG[i]} ${_CONFIG[((i+1))]}
fi
done
if [[ -n ${SECTION} ]]
then
for ((i=0; i<${#_CONFIG[@]}; i+=2))
do
if [[ ${_CONFIG[$i]} =~ ^${SECTION}\.(.+) ]]
then
echo ${_CONFIG[i]} ${_CONFIG[((i+1))]}
fi
done
else
for ((i=0; i<${#_SECTION[@]}; i++))
do
echo ${_SECTION[i]}
done
fi
}

# getProperty [name|section.name]
#
# Print value for given property (sepcified as $1)
# Print value for given property (sepcified as $1)
# Properties without a section can be queried directly as
# "name" (rather than ".name")
#
Expand All @@ -218,7 +240,7 @@ function getProperty() {

# getPropertyVar <variable> [name|section.name]
#
# Save value for given property (sepcified as $2)
# Save value for given property (sepcified as $2)
# into shell variable (specified as $1)
# Properties without a section can be queried directly as
# "name" (rather than ".name")
Expand All @@ -244,20 +266,19 @@ function getPropertyVar() {

function testIniParser() {
echo $ parseIniFile \< test/t2.ini
parseIniFile < test/t2.ini
parseIniFile < ./test/t2.ini
echo $ listKeys
listKeys
echo $ listAll
listAll
echo $ listSection section1
listSection section1
echo $ getProperty global
getProperty global
echo $ getProperty section2.xyz
getProperty section2.xyz
listSection
echo $ getProperty abc
getProperty abc
echo $ getProperty section1.abc
getProperty section1.abc
echo $ getPropertyVar XYZ section2.xyz \&\& echo OK
getPropertyVar XYZ section2.xyz && echo OK
echo $ echo ">\${XYZ}<"
echo ">${XYZ}<"
}