Bash

更簡單地處理 shell 腳本選項

  • May 26, 2020

我正在尋找處理 shell 腳本參數的方法,它比 getopt/getopts 更乾淨、更“自我記錄”。

它需要提供…

  • 完全支持在 ‘=’ 或 ’ ‘(空格)之後帶或不帶值的長選項。
  • 正確處理帶連字元的選項名稱(即 –ignore-case)
  • 正確處理帶引號的選項值(即 –text “A text string”)

我想用 getopt/getopts 需要的嵌入式 case 語句消除大循環的成本,並將選項處理減少到類似…

option=argumentparse "$@"
[[ option == ""           ]] && helpShow
[[ option =~ -h|--help    ]] && helpShow
[[ option =~ -v|--version ]] && versionShow
[[ option =~ -G|--GUI     ]] && GUI=$TRUE
[[ option =~ --title      ]] && TITLE=${option["--title"]}

在這裡,argumentparse() 函式將各種語法可能性解析為一致的格式,可能是關聯數組。

那裡一定有什麼編碼的東西。有任何想法嗎?

(更新並重命名)

由於這個問題已經被查看了這麼多(至少對我來說),但沒有送出答案,傳遞採用的解決方案……

注意

一些函式,如多介面輸出函式ifHelpShow()uiShow()在此處使用但不包括在內,因為它們的呼叫包含相關資訊,但它們的實現不包含相關資訊。

###############################################################################
# FUNCTIONS (bash 4.1.0)
###############################################################################

function isOption () {
 # isOption "$@"
 # Return true (0) if argument has 1 or more leading hyphens.
 # Example:
 #     isOption "$@"  && ...
 # Note:
 #   Cannot use ifHelpShow() here since cannot distinguish 'isOption --help'
 #   from 'isOption "$@"' where first argument in "$@" is '--help'
 # Revised:
 #     20140117 docsalvage
 # 
 # support both short and long options
 [[ "${1:0:1}" == "-" ]]  && return 0
 return 1
}

function optionArg () {
 ifHelpShow "$1" 'optionArg  --option "$@"
   Echo argument to option if any. Within "$@", option and argument may be separated
   by space or "=". Quoted strings are preserved. If no argument, nothing echoed.
   Return true (0) if option is in argument list, whether an option-argument supplied
   or not. Return false (1) if option not in argument list. See also option().
   Examples:
       FILE=$(optionArg --file "$1")
       if $(optionArg -f "$@"); then ...
       optionArg --file "$@"   && ...
   Revised:
       20140117 docsalvage'  && return
 #
 # --option to find (without '=argument' if any)
 local FINDOPT="$1"; shift
 local OPTION=""
 local ARG=
 local o=
 local re="^$FINDOPT="
 #
 # echo "option start: FINDOPT=$FINDOPT, o=$o, OPTION=$OPTION, ARG=$ARG, @=$@" >&2
 #
 # let "$@" split commandline, respecting quoted strings
 for o in "$@"
 do
   # echo "FINDOPT=$FINDOPT, o=$o, OPTION=$OPTION, ARG=$ARG" >&2
   # echo " o=$o"  >&2
   # echo "re=$re" >&2
   #
   # detect --option and handle --option=argument
   [[ $o =~ $re ]]  && { OPTION=$FINDOPT; ARG="${o/$FINDOPT=/}"; break; }
   #
   # $OPTION will be non-null if --option was detected in last pass through loop
   [[ ! $OPTION ]]  && [[ "$o" != $FINDOPT ]]   && {              continue; } # is a positional arg (no previous --option)
   [[ ! $OPTION ]]  && [[ "$o" == $FINDOPT ]]   && { OPTION="$o"; continue; } # is the arg to last --option
   [[   $OPTION ]]  &&   isOption "$o"          && {                 break; } # no more arguments
   [[   $OPTION ]]  && ! isOption "$o"          && { ARG="$o";       break; } # only allow 1 argument
 done
 #
 # echo "option  final: FINDOPT=$FINDOPT, o=$o, OPTION=$OPTION, ARG=$ARG, @=$@" >&2
 #
 # use '-n' to remove any blank lines
 echo -n "$ARG"
 [[ "$OPTION" == "$FINDOPT" ]]   && return 0
 return 1
}

###############################################################################
# MAIN  (bash 4.1.0) (excerpt of relevant lines)
###############################################################################

# options
[[ "$@" == ""            ]]   && { zimdialog --help           ; exit 0; }
[[ "$1" == "--help"      ]]   && { zimdialog --help           ; exit 0; }
[[ "$1" == "--version"   ]]   && { uiShow "version $VERSION\n"; exit 0; }

# options with arguments
TITLE="$(optionArg --title  "$@")"
TIP="$(  optionArg --tip    "$@")"
FILE="$( optionArg --file   "$@")"

引用自:https://unix.stackexchange.com/questions/65160