本文最后更新于 2023-03-14T00:12:48+08:00
最近需要写脚本封装 helm ,批量进行 k8s 服务的部署。需解析命令行参数场景较复杂。
本文列举各种解析Linux命令行参数三种方式优缺点,及使用限制。
Linux 解析命令行参数有三种方式
直接处理
1 2 3 4 5 6 7 8 9 10 11 $0 $1 ,$2 ,$3 ,$4 ... $# $@ $*
getopts
getopts
是bash
的内部命令
“getopts ‘:a:b:c:d:ef’”,识别选项字符串
"第一个:
"消除警告信息。如果命令行中包含了没有在getopts列表中的选项,会有警告信息,在整个getopts字符串前面加上:
就可消除警告信息
"字母后面:
"表示参数,一个冒号就表示这个选项后面必须带有参数,不带:
表示不需要参数
a|b|c|d|e|f
对应到命令行就是-a ,-b ,-c ,-d, -e ,-f。
OPTARG
,用来取当前选项的值,另外一个是
OPTIND
,代表当前选项在参数列表中的位移
?
,代表这如果出现了不认识的选项,所进行的操作。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #!/bin/bash while getopts ':a:b:c:d:ef' OPT; do case $OPT in a) echo "$OPT arg is $OPTARG " ;; b|c|d) echo "$OPT arg is $OPTARG " ;; e) echo "$OPT enabled" ;; f) echo "$OPT enabled" ;; ?) echo "Usage: `basename $0 ` [options] filename" esac done shift $(($OPTIND - 1 ))echo $@
1 2 3 4 5 6 7 8 9 ➜ ./getopts.sh -a aaa -b bbb -c ccc -d ddd -e -f hello world a arg is aaa b arg is bbb c arg is ccc d arg is ddd e enabled f enabled hello world
getopt
getopt
是一个外部命令,但通常Linux发行版会自带
注意:mac下的getopt由BSD实现,Linux则是gnu,不兼容(这里踩了很久的坑,为啥 mac 、Linux 总有一边报错-.-)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 brew install gnu-getopt brew link --force gnu-getoptif [[ `uname ` == 'Darwin' ]]; then echo "Mac OS" GETOPT=`/usr/local/Cellar/gnu-getopt/2.38.1/bin/getopt`elif [[ `uname ` == 'Linux' ]]; then echo "Linux" GETOPT=`getopt`else echo 'OS error' exit 1fi
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 getopt --help 用法: getopt optstring parameters getopt [options] [--] optstring parameters getopt [options] -o|--options optstring [options] [--] parameters 选项: -a, --alternative 允许长选项以 - 开始 -h, --help 这个简短的用法指南 -l, --longoptions <长选项> 要识别的长选项 -n, --name <程序名> 将错误报告给的程序名 -o, --options <选项字符串> 要识别的短选项 -q, --quiet 禁止 getopt(3) 的错误报告 -Q, --quiet-output 无正常输出 -s, --bash <bash> 设置 bash 引用规则 -T, --test 测试 getopt(1) 版本 -u, --unquoted 不引用输出 -V, --version 输出版本信息
-o或–options选项后面是可接受的短选项,如ab:c::,表示可接受的短选项为-a -b -c,
-l或–long选项后面是可接受的长选项,用逗号分开,冒号的意义同短选项。
:
冒号表示参数,一个冒号就表示这个选项后面必须带有参数(没有带参数会报错),但是这个参数可以和选项连在一起写,也可以用空格隔开,比如-a123 和-a 123(中间有空格) 都表示123是-a的参数;
不带:
表示不需要参数
::
表示这个选项的参数是可选的,即可以有参数,也可以没有参数,但要注意有参数时,参数与选项之间不能有空格(有空格会报错),这一点和一个冒号时是有区别的。
如果短选项带参数且参数可选时,参数必须紧贴选项,例如-carg而不能是-c arg
如果长选项带参数且参数可选时,参数和选项之间用“=”,例如–clong=arg而不能是–clong arg
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #!/bin/bash echo "传入参数:$@ " ARGS=`getopt -o ab:c:: --long along,blong:,clong:: -n "$0 " -- "$@ " `if [ $? -ne 0 ]; then echo "getopt error ..." exit 1fi set -- ${ARGS} echo "排列后参数:$@ " while true do case "$1 " in -a|--along) echo "$1 is enabled" ; shift ;; -b|--blong) echo "$1 arg is $2 " ; shift 2 ;; -c|--clong) case "$2 " in "" ) echo "$1 is enabled" ; shift 2 ;; *) echo "$1 arg is $2 " ; shift 2; ;; esac ;; --) shift break ;; *) echo "Internal error!" exit 1 ;; esac done echo "剩余参数:$@ "
1 2 3 4 5 6 7 8 9 10 11 12 13 ➜ ./getopt.sh -a -b bbb -c -cccc hello world --along --blong bbb --clong=ccc --clong 传入参数:-a -b bbb -c -cccc hello world --along --blong bbb --clong=ccc --clong 排列后参数:-a -b 'bbb' -c '' -c 'ccc' --along --blong 'bbb' --clong 'ccc' --clong '' -- 'hello' 'world' -a is enabled -b arg is 'bbb' -c arg is '' -c arg is 'ccc' --along is enabled --blong arg is 'bbb' --clong arg is 'ccc' --clong arg is '' 剩余参数:'hello' 'world'
getopt getopts 区别
getopt
getopts
支持短选项
✅
❌
支持长选项
✅
❌
支持可选参数
✅
❌
参数重排序
✅
❌
case
-a|–along)
a)
参数顺序
任意顺序
所有选项参数必须写在其它参数的前面
每处理完一个位置参数后都需要自己shift
来跳到下一个位置
在最后使用 shift $(($OPTIND - 1))
来跳到parameters的位置
外部命令,通常Linux发行版会自带
bash内部命令
总结
简单脚本可以直接处理
大多数情况使用getopts
处理复杂场景使用getopt