123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #!/bin/bash
-
- ffoo import core
-
-
- #
- # Expected filename extension (for guessing from -p path head)
- #
- # If no filename to read is given, iniread will guess filename
- # as the path head plus this suffix (e.g. `foo.ini` for
- # `iniread -p foo.bar.baz`)
- #
- FFOO_INI_SUFFIX=".ini"
-
-
- __iniread__cat() {
- # cat without starting a process
- while IFS= read line;
- do echo "$line"; done
- }
-
-
- __initead_fltcmt() {
- grep -v -e "^[[:space:]]*[#;]" -e "^[[:space:]]*$"
- }
-
-
- __iniread__fltkey() {
- # filter values from key=value pair
- local line
- local key
- local value
- while IFS= read line;
- do
- line=$(sed -re 's/^\s*//' <<<"$line")
- key=$(sed -re 's/\s*=.*//; s/^\s*//' <<<"$line")
- if $strict;
- then
- value=$(sed -re 's/[^=]*=//' <<<"$line")
- else
- value=$(sed -re 's/[^=]*=\s*//' <<<"$line")
- fi
- if test "$key" = "$wntkey";
- then
- echo "$value"
- fi
- done
- }
-
-
- __iniread__fltsct() {
- # filter per section
- local sct_ok=false
- local line
- while IFS= read line;
- do
- if grep -qse "^\[$wntsct\]" <<<"$line";
- then
- sct_ok=true
- elif grep -qse "^\[" <<<"$line";
- then
- sct_ok=false
- elif $sct_ok;
- then
- $strict || line="$(sed -re 's/^\s*//' <<<"$line")"
- echo "$line"
- fi
- done
- }
-
-
- __iniread__merge() {
- if test -z "$1";
- then # guess filename from section head
- local guess="$(cut -d. -f1 <<<"$wntsct")$FFOO_INI_SUFFIX"
- debug -v guess
- __iniread__merge "$guess"
- fi
- local arg trydir trypath
- for arg in "$@";
- do
- case $arg in
- -|*/*) # stdin, or path (with slash)
- cat $arg
- ;;
- *) # name given, find all its incarnations
- debug -v FFOO_INI_PATH
- echo "$FFOO_INI_PATH" \
- | tr ':' '\n' \
- | while read trydir;
- do
- test -z "$trydir" && continue
- trypath="$trydir/$arg"
- debug -v trypath
- cat $trypath 2>/dev/null
- done
- ;;
- esac
- done
- true
- }
-
-
- iniread() {
- #
- # A flexible (not just) .ini file reader
- #
- # Usage:
- # iniread [-S] [-1] [-s section] [-k key] [file...]
- # iniread [-S] [-1] [-p path] [file...]
- #
- # With *file* as only argument, iniread only throws away
- # comments (i. e. lines starting with "#") and empty lines.
- #
- # Probably most apparent use case is selection of key from
- # a section of INI file. This can be achieved using
- # *path*, which is equivalent to providing both *key* and
- # *section* (i.e. `-p section.key` is the same as
- # `-s section -k key`).
- #
- # However, you can also provide only *section* to select
- # only that section (leaving any key=value pairs intact),
- # or provide only *key* to select only that key from *all*
- # sections in file (if there are any). This in fact extends
- # use of this function beyond just INI-like format: if you
- # are brave enough, you could e.g. query a shell script
- # for a variable assignment (i.e. key=value pair).
- #
- # If suitable key is found at multiple lines, all values
- # are printed, unless you provided *-1* option. This allows
- # for creating multi-line values.
- #
- # Leading/trailing spaces and empty lines are removed from
- # output by default, but strict mode (*-S* or *--strict*
- # switch) changes this behavior so that in theory you can
- # have e.g. a PEP8-compliant Python script inside an INI
- # file.
- #
- # If *file* argument contains slash, it is expanded as a
- # regular path. Alternatively, `-` (single dash) can be
- # specified, which results in STDIN being read instead.
- #
- # If *file* argument does not contain slash, it is searched
- # in directories given in `$FFOO_INI_PATH`, and any files
- # that are found are simply concatenated. (This means
- # that if section is queried that is present in both files,
- # it is effectively concatenated as well.
- #
- # In case of multiple *file* arguments, each is processed
- # separately as indicated above, and result is concatenated
- # before filtering.
- #
- # Without *file* given at all, same procedure is used as
- # in case of filename without slash, except that *file*
- # argument is inferred by taking part of section name
- # before first dot and adding `$FFOO_INI_SUFFIX`, which
- # is ".ini" by default. This allows for creating relatively
- # rich config value structure, having it divided in several
- # files (e.g. by component) and from within your scripts,
- # still accessing them with as little typing as possible.
- #
- local wntsct=""
- local wntkey=""
- local strict=false
- local sct_ok=true
- local one_line=false
- local grepex="." # i.e. throw away empty lines
- while true; do case $1 in
- --) break ;;
- -1|--one-line) one_line=true; shift 1 ;;
- -k|--key) wntkey="$2"; shift 2 ;;
- -p|--path) wntkey="${2##*.}"; wntsct="${2%.$wntkey}"; shift 2 ;;
- -s|--section) wntsct="$2"; sct_ok=false; shift 2 ;;
- -S|--strict) strict=true; shift 1 ;;
- -l|-L) warn "--list-* not implemented yet"; shift 1 ;;
- *) break ;;
- esac done
- fltsct=__iniread__cat
- fltkey=__iniread__cat
- fltcmt=__initead_fltcmt
- limit_line=__iniread__cat
- test -n "$wntsct" && fltsct=__iniread__fltsct
- test -n "$wntkey" && fltkey=__iniread__fltkey
- $one_line && limit_line="tail -1"
- $strict && grepex=""
- $strict && fltcmt=__iniread__cat
- debug -v wntkey wntsct
- debug "\$@='$@'"
- __iniread__merge "$@" \
- | $fltcmt \
- | $fltsct \
- | $fltkey \
- | $limit_line \
- | grep "$grepex"
- #TODO: list keys as section/key (with -s, list keys only)
- }
|