zoukankan      html  css  js  c++  java
  • getopts 的简单模拟(09.12 Rev)

           鉴于有些老版本的 busybox 可能没带 getopts 或 getopt 工具,为了写个支持选项的通用脚本,写个函数模拟 getopts,相比之前 shell 的选项解析 中的处理方式,这样也许更简单易用

    关于 getopts 与 getopt

           处理命令行参数是个相似而又复杂的事,为此,C 提供了 getopt/getopt_long 等函数,C++ 的 boost 提供了 options 库,shell 中处理此事的是 getopts 和 getopt
          getopts 是 Shell 内置(builtin)命令,只支持短选项,而 getopt 属于外部命令,支持长短选项(绕开了 getopts 不符合 Linux 约定的限制),并具有一些 getopts 没有的特性

    getopts 的惯用法

    格式: getopts  option_string  opt_var  [args...],若无 args,则获取命令行参数
    样例:
    while getopts ":a:bc" opt  ##  第一个冒号表示忽略错误;字符后的冒号表示该选项带一个参数
    do
            case $opt in  ## opt 保存了解析出的选项名
                    a ) echo $OPTARG  ## OPTARG 存储选项所带的参数
                        echo $OPTIND;;  ## OPTIND 存储下一个待处理选项在最初列表中的位置
                    b ) echo "b $OPTIND";;
                    c ) echo "c $OPTIND";;
                    ? ) echo "error"
                        exit 1;;
            esac
    done
    shift $(($OPTIND - 1))  ## 这样 $* 就只保留除去选项的参数

          getopts 使用了两个隐含变量:一个是 OPTARG,用来取当前选项的参数,另外一个是 OPTIND(选项索引),用来取要处理的下一个选项,初始值为 1。这与 libc 中的 getopt 函数实现相近,可参考这篇:getopt 函数分析
          若 options-strings 开始有冒号(忽略错误),则
    a. 当指定的选项不存在时,opt_var 设置为 ":",对应的 $OPTARG 为"对应的选项"
    b. 指定的选项带参数的而没有提供参数,opt_var 设为"?",对应的 $OPTARG 为"这时候的选项"
    可以根据这两个选项指定不同的反馈信息

    实现

          这里用全局变量来保存处理状态,_ARGS_ 保存待处理的命令行参数(内部使用),ARGS_保存其中非选项参数,OPT_VAR 保存识别出的选项,OPT_ARG 保存选项所带的参数,若选项不带参则为空。使用时当然自定义变量不能与之重名,否则程序行为将变为非线性。。。

          相比 getopts,有些特性没了,如 silent 模式,但增加了对长选项的简单支持,带参的长选项需写为 --long-opt=opt-arg 的形式;也支持连续选项,即类似 tar 的 -xvf 写法

     1 _ARGS_="$@"
     2 ARGS_=""
     3 OPT_VAR=""
     4 OPT_ARG=""
     5 
     6 ERR_ILLEGAL_OPT=65
     7 ERR_OPT_NEED_VALID_ARG=67
     8 ERR_UNKNOWN_PARA=69
     9 
    10 get_opts()
    11 {
    12    _get_opts "$1" $_ARGS_  ## 转为位置参数
    13    return $?
    14 }
    15 
    16 _get_opts()
    17 {
    18    local opts="$1" && shift  ## 位置参数 1 为 opt-string
    19    OPT_VAR="" && OPT_ARG=""  ## 双清
    20    local arg
    21    for arg in $_ARGS_  ## 寻找待处理选项
    22    do
    23       case $arg in
    24       --* )  ## 1. 长选项
    25             local asn_opt="${arg#--}"
    26             OPT_VAR="${asn_opt%%=*}"
    27             if [ "$OPT_VAR" != "$asn_opt" ]; then
    28                 OPT_ARG="${asn_opt#*=}"
    29                 [ -z "$OPT_ARG" ] && ErrorX $ERR_OPT_NEED_VALID_ARG  ## 若等号后未带参数,则出错退出
    30             fi
    31             ;;
    32       -*  )  ## 2. 短选项 
    33             local the_opt=${arg#-}
    34             local o1=$(expr substr "$the_opt" 1 1)
    35             [ $(expr index "$opts" "$o1") -eq 0 ] && ErrorX $ERR_ILLEGAL_OPT  ## 若解析出的选项在 opt-string 里没找到
    36             OPT_VAR="$o1"
    37             
    38             if [ $(expr match "$opts" ".*${o1}:") -gt 0 ]; then
    39                [ "$o1" != "$the_opt" -o -z "$2" ] && ErrorX $ERR_OPT_NEED_VALID_ARG
    40                OPT_ARG=$2
    41                shift
    42             fi
    43             ;;
    44       *   )  ## 3. 保存非选项参数(显然不支持带空格的参数)
    45             ARGS_="$ARGS_ $arg"
    46             ;;
    47       esac
    48       shift
    49       [ -n "$OPT_VAR" ] && break  ## 若找到选项则 break
    50    done
    51    _ARGS_="$@"  ## 保存剩余待处理参数
    52    [ ${#the_opt} -gt 1 ] && _ARGS_="-${the_opt#?} $_ARGS_"  ## 支持连续选项
    53    [ -n "$_ARGS_" -o -n "$OPT_VAR" ] && return 0 || return 1  ## 若有待处理的参数或选项,则返回 0
    54 }

    其中,ErrorX 是错误处理函数,统一处理错误码,“X”为退出意,当然是否退出可自定义

    用法

    与 getopts 类似,如:

     1 while get_opts "r:w:"
     2 do
     3     case $OPT_VAR in
     4     r  | retry    ) retry=$OPT_ARG;;  ## 重试次数
     5     w | wait    ) interval=$OPT_ARG;;  ## 重试间隔
     6        *        )  ErrorX $ERR_UNKNOWN_PARA;;
     8     esac
     9 done
    10 [ -n "$ARGS_" ] && set $ARGS_  ## 将剩下的非选项参数设为位置参数,方便后继使用

    命令行可写成这样:

    ./tool.sh -r 3 -w 30

    或长选项形式:

    ./tool.sh --retry=3 --wait=30

    看到这篇文章 命令行参数解析,发觉倒和 python 的选项有点像,不过看上去它一次就解析完了,呵呵

    1 opts,args = getopt.getopt(sys.argv[1:],"h:p:",["host=","port="])
    2 for opt,arg in opts:
    3       if opt in ("-h","--host"):
    4           host = arg
    5       if opt in ("-p","--port"):
    6           port = arg
  • 相关阅读:
    You Don't Know JS: Async & Performance(第2章,Callbacks)
    You Don't Know JS: this & Object Prototypes (第6章 Behavior Delegation)附加的ES6 class未读
    C#抓取网页内容
    输出jq对象
    ASP.NET MVC 常用内置验证特性
    MVC不错的学习资料
    让Entity Framework启动不再效验__MigrationHistory表
    多线程
    递归
    序列化
  • 原文地址:https://www.cnblogs.com/lookbackinside/p/2676198.html
Copyright © 2011-2022 走看看