You are not logged in.

#41 Today 08:16:23

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 13,614
Website

Re: bash script function to parse config files

While applying parse_config() to bl-exit for parsing bl-exit.conf I ran into a couple of annoyances in cases where the config was a command line (in this case, an alternative screenlocker command). Finally I dropped attempts to use regex to parse out a usable shell command and just took whatever was on the right hand side of the = sign (minus blanks) and put it in the config array. Users can just write whatever they would have run in a terminal.

But to turn that command line into an array to make it easier to handle is not easy with bash. Eventually I resorted to a bit of python - this copes with quotes, escaped quotes, comments etc - and made a second function parse_array_from_string() for that job.

So this version of parse_config() is a bit simpler:

parse_config(){
    [[ -f $1 ]] || { echo "$1 is not a file." >&2;return 1;}
    local -n config_array="${2:-config}"
    declare -Ag "${!config_array}" || return 1
    local line key value comment_regex section_regex entry_regex
    comment_regex="^[[:blank:]]*#"
    section_regex="^[[:blank:]]*\[[[:blank:]]*([[:alpha:]_][[:alnum:]_]*)[[:blank:]]*\][[:blank:]]*(#.*)?$"
    entry_regex="^[[:blank:]]*([[:alpha:]_][[:alnum:]_-]*)[[:blank:]]*=[[:blank:]]*(.*)$" # take whatever is on the RHS of the =, including comments
    while read -r line
    do
        [[ -n $line ]] || continue
        [[ $line =~ $comment_regex ]] && continue
        [[ $line =~ $section_regex ]] && {
            local -n config_array=${BASH_REMATCH[1]}
            declare -Ag "${!config_array}" || return 1
            continue
        }
        [[ $line =~ $entry_regex ]] || continue
        key=${BASH_REMATCH[1]}
        value=${BASH_REMATCH[2]}
        config_array["${key}"]="${value}"
    done < "$1"
}

and here is parse_array_from_string()

# make an array to hold the command string parsed from the user config file
# Usage: parse_array_from_string <input string> <array name>
parse_array_from_string() {
    local input="$1"
    local result
    local -n result_array="$2"
    result=$(python3 -c "import shlex, sys
text = sys.stdin.read().strip()
tokens = shlex.split(text, comments='#')
if len(tokens) == 1:
    tokens = shlex.split(tokens[0])
print('\n'.join(tokens))
" <<< "$input" 2>&1 ) || {
        yad --text="Syntax error in command:\n$input\n\nDetails:\n$(pangoEscape "$result")" --title="Config Error" --image=dialog-error --name=dialog-error --window-icon=dialog-error
        return 1
    }
    # shellcheck disable=SC2034
    readarray -t result_array <<< "$result"
}

pangoEscape () is needed in case the yad message has unusable characters:

pangoEscape() {
    local string="${1//&/\&amp;}"
    string="${string//</\&lt;}"
    string="${string//>/\&gt;}"
    printf '%s' "$string"
}

In bl-exit they are used like this to generate LOCK_SCREEN_COMMAND :

parse_config "$user_config_file"
###
case $session_type in
x11)
    LOCK_SCREEN_COMMAND=("${XORG_LOCK_SCREEN_COMMAND[@]}")
    [[ -n "${settings[XORG_LOCK_SCREEN_COMMAND]}" ]] && parse_array_from_string "${settings[XORG_LOCK_SCREEN_COMMAND]}" LOCK_SCREEN_COMMAND
    ;;
wayland)
    LOCK_SCREEN_COMMAND=("${WAYLAND_LOCK_SCREEN_COMMAND[@]}")
    [[ -n "${settings[WAYLAND_LOCK_SCREEN_COMMAND]}" ]] && parse_array_from_string "${settings[WAYLAND_LOCK_SCREEN_COMMAND]}" LOCK_SCREEN_COMMAND
    ;;
esac

Last edited by johnraff (Today 08:19:21)


...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky and Mastodon, there's also some GitStuff )

Introduction to the Bunsenlabs Boron Desktop

Offline

Board footer

Powered by FluxBB