#!/bin/bash # http://en.wikipedia.org/wiki/INI_file: # * Provides a good explanation of the ini format - use this for docs * # * INI's have 'sections' and 'properties'. Properties have key = value format * # # Case insensitivity: Case is not changed, unless option used to covert to lower/upper case. # Comments: Allow ; and # for comments. Must be on their own line. # Blank lines: Blank lines are ignored. # Escape chars: \ at the end of a line will continue it onto next (leading whitespace is removed per normal) # Ordering: GLOBAL section must be at the top, sections continue until next section or EOF. # Duplicate names: Duplicate property values overwrite previous values. # Provide an option to abort/error is duplicate is found? # Add option to merge duplicates separated by octal byte (\036 ??) # Duplicate sections are merged. Option to error if dup. # Global properties: Support. Add to a GLOBAL section? # Hierarchy: No hierarchy support. Each section is own section. # Name/value delim: Use = by default. Allow : via option? # Quoted values: Allow values to be within " and ' to keep literal formatting. # Whitespace: Whitespace around section labels and []s is removed. # Whitespace within section labels is kept / translated. # Whitespace around property names is removed. # Whitespace within property names is kept as is (spaces squashed - option to override). # Property values have whitespace between = and data removed. # Property values are kept as is (no squashing) # http://www.regular-expressions.info/posixbrackets.html # http://ajdiaz.wordpress.com/2008/02/09/bash-ini-parser/ # https://github.com/rudimeier/bash_ini_parser/blob/ff9d46a5503bf41b3344af85447e28cbaf95350e/read_ini.sh # http://tldp.org/LDP/abs/html/ # Specs: # [section] Can be upper/lower/mixed case (set by options) # Can only include: '-+_. [:alnum:]' # # Any single or consecutive occurance of '-+_. ' are converted to a *single* _ # # eg: [foo -+_. bar] becomes [foo_bar] ?? # Any leading/trailing spaces/tabs between the []s and name will be removed. # Notes: # * To make env vars available to subsequent programs, use -x|--export. parser_getopts() { local DELIM_SET=0 while [[ ! -z "$1" ]]; do case "$1" in -b|-bound|--bound) shift if [[ -z "$1" ]]; then echo "${0##*/}: bound (-b) cannot be an empty value" >&2 return 1 elif ((${#1} > 1)); then echo "${0##*/}: bound (-b) must be a single character" >&2 return 1 else KEYVALUE_DELIM="$1" fi shift ;; -d|-delim|--delim) shift if [[ -z "$1" ]]; then VARIABLE_DELIM="" DELIM_SET=1 elif [[ -z "$VARIABLE_PREFIX" ]] && [[ "${1:0:1}" =~ [[:digit:]] ]]; then echo "${0##*/}: delim (-d) cannot begin with a number when prefix (-p) is empty" >&2 return 1 elif [[ "$1" =~ [^[:alnum:]_] ]]; then echo "${0##*/}: invalid characters in delim (-d) - alphanumerics and _ only" >&2 return 1 else VARIABLE_DELIM="$1" DELIM_SET=1 fi shift ;; -h|-help|--help) parser_help return 0 ;; -p|-prefix|--prefix) shift if [[ -z "$1" ]]; then if [[ "${VARIABLE_DELIM:0:1}" =~ [[:digit:]] ]]; then echo "${0##*/}: prefix (-p) cannot be empty if delim (-d) begins with a number" >&2 return 1 else VARIABLE_PREFIX="" if ((DELIM_SET == 0)); then VARIABLE_DELIM="" fi fi elif [[ "${1:0:1}" =~ [[:digit:]] ]]; then echo "${0##*/}: prefix (-p) cannot begin with a number" >&2 return 1 elif [[ "$1" =~ [^[:alnum:]_] ]]; then echo "${0##*/}: invalid characters in prefix (-p) - alphanumerics and _ only" >&2 return 1 else VARIABLE_PREFIX="$1" fi shift ;; -v|-version|--version) parser_version return 0 ;; --) # Stop option processing. break ;; --*|-*) echo "${0##*/}: invalid option: $1" return 1 ;; *) break ;; esac done # Make sure we have an INI file after all the options are removed. if (($# == 0)) || (($# > 1)) || [[ -z "$1" ]]; then echo "Usage: ${0##*/} [options] " >&2 echo "Try: ${0##*/} --help" >&2 return 1 else INIFILE="$1" fi } parser_help() { #........1.........2.........3.........4.........5.........6.........7.........8 cat <<-EOF Usage: ${0##*/} [options] Parse an INI-style file into array assignments which can be 'eval'ed into Bash. Options: -b , --bound The bound character which delimits the key from the value in a property line of the INI file. The default is "=". This must be a single character and cannot be empty value. -d , --delim The character(s) to use as a delimiter between the prefix and section name when defining the arrays. The default is "_", except where prefix is set to an empty value, in which case the default is also empty. Only alphanumerics and _ may be used with this option, and it may not begin with a number if prefix is empty. To use no delimintaor, use '-d ""'. -p , --prefix The prefix of all the variables set when defining the arrays. The default is "INI". An empty prefix (denoted by "") implies '-d ""', but this can be overridden by explicitly specifying a delimiter with '-d'. Only alphanumerics and _ may be used with this option, and it may not be empty when delim ('-d) begins with a number. -i, --implied-boolean Options usually require a value (after the =) in order to be set. With this option, any key without a value contained in the ini file if assumed to be a boolean 'true' and set accordingly. Likewise, any key preceeded with 'no_' (eg: no_foo) will set the value of 'foo' to boolean 'false'. Cannot be used with --no-boolean. -c, --case-sensitive Be case sensitive with section names and properties. Section names and property names will be used as is - no translation. -d, --delim The delimiter between the key and value. Must be a single character. Default = -g, --global-name INI files can contain an optional implied "global" section - where there are property names/values before any [section] header. This option specified what section name the implied "global" section should be given in the environment variables which are set. The default is 'global'. -l, --lowercase Usually, environment variables are converted to all uppercase before being set. This option forces all environment variables to be converted to lowercase instead. Note: This only effects the environment variable set with -e, and the section names read from the ini file. Options are ?????????????????????????????????????? -x, --export Export environment variables. --no-boolean Don't parse 'yes', 'true', 'on', 'no', 'false', 'off' into the corresponding boolean values, and set the options strictly as is. Incompatible with -i. --no-squash Do not squash multiple consecutive occurances of punctuation characters into a single _ when parsing section names and options. With this option 'foo.-_bar' would become 'foo___bar' rather than 'foo_bar'. --no-duplicates If a duplicate section name or option name is found, report error and stop. Usually sections with the same name will have their options merged, and duplicate option values will overwrite previous ones. # -c, --check-only Only validate the ini file, don't parse it into the environment --check Check/validate the INI file by running it through the parser. Testing the ini file will report any problems or syntax errors in the file, but will not set up the environment variables as would happen in normal parsing. Any parse errors are reported to stderr. When combined with the --debug option, every detail of the parsing process is reported to stderr. --debug Show full details of the ini file parsing process. Detail is written to stderr. Unless --test is used with this option, the parser will still set up the environment as would happen normally, -h, --help Show (this) help. -v, --version Show version and copyright information. # -b, --booleans Allow 'yes', 'true', 'on', 'no', 'false', 'off' to be used as values # and interpited as boolean values. 'yes', 'true', 'on' set option value to "1". # 'no', 'false', 'off' set option value to "0". # -?, --???? Interprite the presense of an option name without any value as a boolean # 'true', and no_