shell的参数解析

getopt

使用规则

bash或zsh getopt_demo.sh 一堆参数 # 其前中后均可有 余参数
  • 格式化参数:即-开头的参数,若无法依照希望的方式解析,就会报错
短参数 长参数
无选项 -a –a-long
必有选项 -boption-b option
-b'op tions'-b 'op tion'
--b-long option
--b-long 'op tion'
可有选项 若无选项 -c --c-long
可有选项 若有选项:
只能用短参数 选项和参数间无空格
-coption
-c'op tion'
--c-long option不可
  • 余参数:即非-开头的参数,可出现在格式化参数之前、之中、之后

例如

bash/zsh getopt_demo.sh -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "

返回

Option a
Option c, no argument
Option c, argument more'
Option b, argument very long '
Remaining arguments:
--> par1'
-->another arg'
--> `wow!\?'

代码写法

getopt_demo.sh内容如下

#!/bin/bash

# 使用规则
# bash/zsh getopt_demo.sh 一堆参数,其前中后均可有 余参数
# 格式化参数:以'-'开头,必需符合本代码的解析要求
    #             短参数                           长参数
    # 无选项       -a                              --a-long
    # 必有选项     -bss          -b ss             --b-long ss
    #             -b'sds sds'   -b 'sds sds'      --b-long 'sds sds'
    # 可有选项若无  -c                              --c-long
    # 可有选项若有  -css          -c'sds sds'  只可短参数,选项与参数间不得有空格
# 余参数:不以'-'开头


# 参数预处理
TEMP=$(getopt \
    -o      ab:c:: \
    --long  a-long,b-long:,c-long:: \
    -n      '参数解析错误' \
    -- s    "$@")
# 写法
    #   -o     短参数 不需要分隔符
    #   --long 长参数 用','分隔
    #   ``无选项  `:`必有选项  `::` 可由选项
if [ $? != 0 ] ; then echo "格式化的参数解析错误,正在退出" >&2 ; exit 1 ; fi
eval set -- "$TEMP" # 将复制给 $1, $2, ...


# 处理参数
while true ; do case "$1" in
    # 无选项
    -a|--a-long)  echo opt a ; shift ;;
    # 必有选项
    -b|--b-long)  echo opt b arg "$2" ; shift 2 ;;
    # 可省选项
    -c|--c-long) case "$2" in
        # 无选项
        "")  echo opt c no arg ; shift 2 ;;
        # 有选项
        *)   echo opt c arg "$2" ; shift 2 ;;  esac ;;
    # '--'后是 余参数
    --) shift ; break ;;
    # 处理参数的代码错误
    *) echo "参数处理错误" ; exit 1 ;;
esac ; done


# 余下参数
for i in "$@"; do
   echo rest "$i"
done

snippets

为了方便些getopt,我已经将上述模板写成sublime、vscode、vim的snippet

徒手解析

while test $# -gt 0; do
    case "$1" in
        -<短参数1>)  相应代码 ;; # 短参数
        -<短参数2>)  相应代码 ;; # 短参数
        --<长参数1>) 相应代码 ;; # 长参数
        --<长参数2>) 相应代码 ;; # 长参数
        -*)         相应代码 ;; # 剩余短参数
        --*)        相应代码 ;; # 剩余长参数
        *)          相应代码 ;; # 非参数
    esac
    shift
done

注:

  • ;;前可以换行,详见下
  • -某某) 后可以换行,详见下
  • 相应代码可以再接受参数,例如
-<短参数1>)
    if [ "${2:0:1}" != '-' ]; then
        相应代码来处理$2
        shift
    fi
    ;;

缺点:

  • 仅此一个:不支持解析相邻的短参数 -lAd,必需写成-l -A -d