linux sh : get ini config file's section key's value
发布日期:2021-06-30 22:17:08 浏览次数:2 分类:技术文章

本文共 11629 字,大约阅读时间需要 38 分钟。

前言

想在linux脚本安装程序中使用配置文件, 用ini格式吧。

先去找找实现,实在不行,就自己写一个挫的实现。
在github上查到一个实现,作者的思路是传进脚本函数一个回调函数,遍历ini时,调用用户传入的回调函数,由调用者去处理遍历的结果,而且那个回调函数名称和要取的key-value有关,这不现实啊。
在原版实现的基础上加了一个函数shini_get_section_key_s_value(),指定ini_path_name,section_name, key_name, 返回value 和错误码.

运行效果

execute make_linux_installation_program.sh...ok : shini_get_section_key_s_value exist, can call it--------section:key=[2.2hello for installer]--------execute make_linux_installation_program.sh END

实现

#!/bin/bash --posix# @file make_linux_installation_program.sh. ./helper/sh.ini_file_opt. ./helper/sh.env_checkfunction main() {    local rv=""    local rc=0    local str_cmd=""    clear    echo "execute make_linux_installation_program.sh..."    # rv=$(func_is_sh_function_exist) # test case    # rv=$(func_is_sh_function_exist "") # test case    rv=$(func_is_sh_function_exist "shini_get_section_key_s_value")    rc=$?    if [ 0 -ne $rc ]    then        echo "$rv"        return $rc    else        echo "ok : shini_get_section_key_s_value exist, can call it"    fi    # test case    # rv=$(shini_get_section_key_s_value) # case : parameter counter isn't 3    # rv=$(shini_get_section_key_s_value "" "section2" "value2") # case : ini file name is empty    # rv=$(shini_get_section_key_s_value "./config/installer_not_exist.ini" "section2" "value2") # case : ini file not exist    # rv=$(shini_get_section_key_s_value "./config/installer.ini" "section_not_exist" "value2") # case : section not exist    # rv=$(shini_get_section_key_s_value "./config/installer.ini" "section2" "value_not_exist") # case : key not exist    rv=$(shini_get_section_key_s_value "./config/installer.ini" "section2" "value2") # case : section, key was all exist    rc=$?    if [ $rc -eq 0 ]    then        echo --------        echo "section:key=[$rv]"        echo --------    else        echo ...        echo "not find section's key value"        echo "rc=$rc : rv=$rv"        echo ...    fi    echo "execute make_linux_installation_program.sh END"    return 0}mainexit 0
#!/bin/bash --posix# @file sh.evn_check# multiple line comment, "<
#!/bin/bash --posix# @file sh.ini_file_opt# shini - compatible INI library for sh## This code is released freely under the MIT license - see the shipped LICENSE document.# For the latest version etc, please see https://github.com/wallyhall/shini## Solely for the purpose of portable performance, this script breaks good practice to# avoid forking subshells.  One such good practice is avoiding global variables.# This variable is used to carry non-numeric results from functions to the caller.# Alternatively an echo and "$(...)" approach could be used, but is significantly slower.shini_setup(){    if [ -n "$ZSH_VERSION" ]; then        RESTORE_OPTS=$(set +o)        # Enable BASH_REMATCH for zsh        setopt KSH_ARRAYS BASH_REMATCH    fi}shini_teardown(){    [ -n "$ZSH_VERSION" ] && eval "$RESTORE_OPTS"}shini_function_exists(){    type "$1" > /dev/null 2>&1    return $?}shini_regex_match(){    # $KSH_VERSION (I'm told) only exists on ksh 93 and above, which supports regex matching.    if [ -n "$BASH_VERSINFO" ] && [ "$BASH_VERSINFO" -ge 3 ] || \       [ -n "$ZSH_VERSION" ] || \       [ -n "$KSH_VERSION" ]; then        [[ "$1" =~ $2 ]] && return 0 || return 1    fi    printf '%s' "$1" | grep -qe "$2"    return $?}shini_regex_replace(){    if [ -n "$BASH_VERSINFO" ] && [ "${BASH_VERSINFO}" -ge 3 ] || \       [ -n "$ZSH_VERSION" ]; then        [[ "$1" =~ $2 ]] && shini_retval=${BASH_REMATCH[1]} || shini_retval="$1"        return 0    fi    shini_retval="$(printf '%s' "$1" | sed -E "s/$2/\1/")"  # If you have isses on older systems,    # it may be the non-newer POSIX compliant sed.    # -E should be enabling extended regex mode portably.}# @param inifile Filename of INI file to parse# @param postfix Function postfix for callbacks (optional)# @param extra Extra argument for callbacks (optional)shini_parse(){    shini_parse_section "$1" '' "$2" "$3" "$4" "$5"}# @param inifile Filename of INI file to write to# @param section Section of INI file to write to# @param variable Variable name to add/update/delete# @param value Value to add/update, do not specify to deleteshini_write(){    shini_setup    # ********    # This is not yet optimised (early write support only) -     # We actually re-parse the entire file, looking for the location in which to    # write the new value, writing out everything we parse as-is meanwhile.    # Declare the following if you want particular behaviour (like skipping    # broken INI file content or handling an unreadable file etc).    #  __shini_no_file_passed__writer()    #  __shini_file_unreadable__writer()    #  __shini_parse_error__writer()    # Writer callbacks, used for writing the INI file content    __shini_parsed_section__writer()    {        # Validate the last section wasn't the target section        if [ "$LAST_SECTION" = "$WRITE_SECTION" ]; then            # If it was, and the value wasn't written already, write it            if [ $VALUE_WRITTEN -eq 0 ]; then                printf "\n%s=%s" "$WRITE_KEY" "$WRITE_VALUE" >> "$INI_FILE_TEMP"                VALUE_WRITTEN=1            fi        fi        printf "\n[%s]" "$1" >> "$INI_FILE_TEMP"        LAST_SECTION="$1"    }    __shini_parsed_comment__writer()    {        printf ";%s" "$1" >> "$INI_FILE_TEMP"    }    __shini_parsed__writer()    {        if [ "$1" = "$WRITE_SECTION" ]; then            if [ "$2" = "$WRITE_KEY" ]; then                if [ ! -z "$WRITE_VALUE" ]; then                    printf "\n%s=%s" "$WRITE_KEY" "$WRITE_VALUE" >> "$INI_FILE_TEMP"                fi                VALUE_WRITTEN=1                return 0            fi        fi        printf "\n%s=%s" "$2" "$3" >> "$INI_FILE_TEMP"        return 0    }    if [ $# -lt 3 ]; then        if shini_function_exists "__shini_no_file_passed"; then            __shini_no_file_passed        else            printf 'shini: Argument 1 needs to specify the INI file to write.\n' 1>&2            return 254        fi    fi    INI_FILE="$1"    INI_FILE_TEMP="$(mktemp -t shini_XXXXXX)"           WRITE_SECTION="$2"    WRITE_KEY="$3"    WRITE_VALUE="$4"    LAST_SECTION=""    VALUE_WRITTEN=0    shini_parse "$1" "_writer" "$2" "$3" "$4"    # Still not written out yet    if [ $VALUE_WRITTEN -eq 0 ]; then        # Check if final existing section was target one, add it if not        if [ "$LAST_SECTION" != "$WRITE_SECTION" ]; then            printf "\n[%s]" "$WRITE_SECTION" >> "$INI_FILE_TEMP"        fi        # Write value at end of file        printf "\n%s=%s" "$WRITE_KEY" "$WRITE_VALUE" >> "$INI_FILE_TEMP"    fi    mv "$INI_FILE_TEMP" "$INI_FILE"    # ********    shini_teardown    return 0}# ----------------------------------------------------------------------------# @fn shini_get_section_key_s_value# @brief get ini file section's key's string value# @note this sh function by lostspeed# @param IN $1 : ini file path name# @param IN $2 : section name# @param IN $3 : key name# @param OUT : echo the value on the section/key# @return OUT : 0 is ok, other is error# ----------------------------------------------------------------------------shini_get_section_key_s_value(){    local argc=$#    local rc=1    shini_setup    # ********    RX_KEY='[a-zA-Z0-9_\-\.]'    RX_VALUE="[^;\"]"    RX_SECTION='[a-zA-Z0-9_\-]'    RX_WS='[    ]'    RX_QUOTE='"'    RX_HEX='[0-9A-F]'    POSTFIX=''    SKIP_TO_SECTION='' # ini section name to find    OBJ_KEY_NAME="" # ini key name to find    # after modify, this function no extra parameter    EXTRA1=''    EXTRA2=''    EXTRA3=''    SECTION_FOUND=-1    if [ 3 -ne $argc ]    then        printf "parameter counter must be 3. e.g. shini_get_section_key_s_value ini_path_name section_name key_name"        rc=255        return $rc    fi    if [ $# -ge 2 ] && [ ! -z "$2" ]; then        SKIP_TO_SECTION="$2"    fi    if [ $# -ge 3 ] && [ ! -z "$3" ]; then        POSTFIX="_$3"        OBJ_KEY_NAME=$3        # echo "to find $SKIP_TO_SECTION : $OBJ_KEY_NAME"    fi    if [ $# -lt 1 ]; then        if shini_function_exists "__shini_no_file_passed{
$POSTFIX}"; then "__shini_no_file_passed${POSTFIX}" "$EXTRA1" "$EXTRA2" "$EXTRA3" else printf 'shini: Argument 1 needs to specify the INI file to parse.\n' rc=254 return $rc fi fi INI_FILE="$1" if [ ! -r "$INI_FILE" ]; then if shini_function_exists "__shini_file_unreadable${POSTFIX}"; then "__shini_file_unreadable${POSTFIX}" "$INI_FILE" "$EXTRA1" "$EXTRA2" "$EXTRA3" else printf 'shini: Unable to read INI file:\n `%s`\n' "$INI_FILE" rc=253 return $rc fi fi # Iterate INI file line by line LINE_NUM=0 SECTION='' while read LINE || [ -n "$LINE" ]; do # -n $LINE catches final line if not empty # Check for new sections if shini_regex_match "$LINE" "^${RX_WS}*\[${RX_SECTION}${RX_SECTION}*\]${RX_WS}*$"; then shini_regex_replace "$LINE" "^${RX_WS}*\[(${RX_SECTION}${RX_SECTION}*)\]${RX_WS}*$" "\1" SECTION=$shini_retval if [ "$SKIP_TO_SECTION" != '' ]; then # stop once specific section is finished [ $SECTION_FOUND -eq 0 ] && break; # mark the specified section as found [ "$SKIP_TO_SECTION" = "$SECTION" ] && SECTION_FOUND=0; fi if shini_function_exists "__shini_parsed_section${POSTFIX}"; then "__shini_parsed_section${POSTFIX}" "$SECTION" "$EXTRA1" "$EXTRA2" "$EXTRA3" fi continue fi # Skip over sections we don't care about, if a specific section was specified [ "$SKIP_TO_SECTION" != '' ] && [ $SECTION_FOUND -ne 0 ] && continue; # Check for new values if shini_regex_match "$LINE" "^${RX_WS}*${RX_KEY}${RX_KEY}*${RX_WS}*="; then shini_regex_replace "$LINE" "^${RX_WS}*(${RX_KEY}${RX_KEY}*)${RX_WS}*=.*$" KEY=$shini_retval shini_regex_replace "$LINE" "^${RX_WS}*${RX_KEY}${RX_KEY}*${RX_WS}*=${RX_WS}*${RX_QUOTE}{0,1}(${RX_VALUE}*)${RX_QUOTE}{0,1}(${RX_WS}*\;.*)*$" VALUE=$shini_retval if shini_regex_match "$LINE" "^0x${RX_HEX}${RX_HEX}*$"; then VALUE=$(printf '%d' "$VALUE") fi # "__shini_parsed${POSTFIX}" "$SECTION" "$KEY" "$VALUE" "$EXTRA1" "$EXTRA2" "$EXTRA3" # 遍历指定section下的key, value # 在这里判断是否找到入参指定的section,key if [ "$SECTION" == "$SKIP_TO_SECTION" ] && [ "$KEY" == "$OBJ_KEY_NAME" ] then echo -e "$VALUE" rc=0 # ok, find section:key's value break fi if shini_function_exists "__shini_parsed_comment${POSTFIX}"; then if shini_regex_match "$LINE" ";"; then shini_regex_replace "$LINE" "^.*\;(.*)$" COMMENT=$shini_retval "__shini_parsed_comment${POSTFIX}" "$COMMENT" "$EXTRA1" "$EXTRA2" "$EXTRA3" fi fi continue fi # Announce parse errors if [ "$LINE" != '' ] && shini_regex_match "$LINE" "^${RX_WS}*;.*$" && shini_regex_match "$LINE" "^${RX_WS}*$"; then if shini_function_exists "__shini_parse_error${POSTFIX}"; then "__shini_parse_error${POSTFIX}" $LINE_NUM "$LINE" "$EXTRA1" "$EXTRA2" "$EXTRA3" else printf 'shini: Unable to parse line %d:\n `%s`\n' $LINE_NUM "$LINE" fi fi LINE_NUM=$((LINE_NUM+1)) done < "$INI_FILE" # ******** shini_teardown return $rc}

转载地址:https://lostspeed.blog.csdn.net/article/details/79338576 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:alg : 3个量杯的问题1
下一篇:linux sh : check sh function is exist; multiple line comment;

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月27日 18时41分37秒