本文共 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}
转载地址:http://oymvf.baihongyu.com/