命令行参数处理函数getopt和getopts
- getopt
getopt是一个外部命令,作用是分析输入参数,转换成格式化的输出字符串。
opts=`getopt -o abc:d: --long aa,bb,cc:,dd: -n "myscript" -- "$@"`
if [ $? != 0 ] ; then echo "Failed parsing options." >&2; exit 1; fi
eval set -- "$OPTS"
举一个例子来说明这个问题:
opts=`getopt -o abc:d: --long aa,bb,cc:,dd: -n "myscript" -- "$@"`
echo "opts=[$opts]"
运行:
$ test.sh -abc ccc -d "ddd1 ddd2"
opts=[ -a -b -c 'ccc' -d 'ddd1 ddd2' --]
结果就是把参数进行了格式化处理,把-abc <cvalue>
分解成独立的-a -b -c <cvalue>
这种标准格式。
方便后面的程序处理参数。
错误的处理:
- 无效参数
getopt打印出错误信息,并返回非零值。
$ opts=`getopt -o :abc:d: --long aa,bb,cc:,dd: -n "myscript" -- "$@"`
if [ $? != 0 ] ; then echo "Failed parsing options." >&2; exit 1; fi
运行:
$ test.sh -abc ccc -d "ddd1 ddd2" -e
myscript: invalid option -- 'e'
Failed parsing options.
参数-e
是一个不支持的参数。
- 缺少参数值
再运行
$ test.sh -abc ccc -d
myscript: option requires an argument -- 'd'
Failed parsing options.
参数-d
需要带一个参数值,但是没有。
但是这里有一个坑:
如果参数不是最后一个参数,那么getopt会把后一个参数名认定是前一个参数的值。
$ test.sh -abc -d dddd
opts=[ -a -b -c '-d' -- 'dddd']
参数-c
需要带一个参数值,但是这里没有,于是getopt把-d
认作是-c
的参数值了,然后往后只能把dddd认作是位置参数了。
- 忽略错误消息
方法是在参数列表最前面加一个冒号(:
),然后getopt就不打印出错误信息,但是getopt的返回值还是非零值,脚本还能判断是否继续。
opts=`getopt -o :abc:d: --long aa,bb,cc:,dd: -n "myscript" -- "$@"`
if [ $? != 0 ] ; then echo "Failed parsing options." >&2; exit 1; fi
运行:
$ test.sh -abc ccc -d
Failed parsing options.
前面我们看到参数-d
缺少参数值,加了(:
)不显示错误信息了,但是getopt命令返回值还是非零,脚本还能从返回值决定后续的操作,
- getopts
getopts是一个builtin命令,而不是一个外部程序。
getopts OPTSTRING VARNAME [ARGS...]
如果可选参数[ARGS...]为空,那么读的就是命令行参数"$@"。
典型用法式用在一个循环里面分析命令行参数:
while getopts "abc:d:" ARG; do
echo "ARG=[$ARG], OPTIND=[$OPTIND] OPTARG=[$OPTARG]"
done
每一次循环返回一个当前参数放入变量flag中,并同时设置全局变量OPTIND和OPTARG表示下一个处理的参数的位置和当前参数值。
运行:
$ test.sh -a -b -c ccc -d "ddd1 ddd2"
ARG=[a], OPTIND=[2] OPTARG=[]
ARG=[b], OPTIND=[3] OPTARG=[]
ARG=[c], OPTIND=[5] OPTARG=[ccc]
ARG=[d], OPTIND=[7] OPTARG=[ddd1 ddd2]
$ test.sh -abc ccc -d "ddd1 ddd2"
ARG=[a], OPTIND=[1] OPTARG=[]
ARG=[b], OPTIND=[1] OPTARG=[]
ARG=[c], OPTIND=[3] OPTARG=[ccc]
ARG=[d], OPTIND=[5] OPTARG=[ddd1 ddd2]
对错误的处理:
不管是不认识的参数,还是参数缺少参数值,getops都会打印错误信息,并把ARG置成一个问号(?
):
$ test.sh -abc ccc -e
ARG=[a], OPTIND=[1] OPTARG=[]
ARG=[b], OPTIND=[1] OPTARG=[]
ARG=[c], OPTIND=[3] OPTARG=[ccc]
test.sh: illegal option -- e
ARG=[?], OPTIND=[4] OPTARG=[]
$ test.sh -abc ccc -d
ARG=[a], OPTIND=[1] OPTARG=[]
ARG=[b], OPTIND=[1] OPTARG=[]
ARG=[c], OPTIND=[3] OPTARG=[ccc]
test.sh: option requires an argument -- d
ARG=[?], OPTIND=[4] OPTARG=[]
如何隐藏错误:同样的在参数列表最前面加一个冒号(:
):
while getopts ":abc:d:" ARG; do
echo "ARG=[$ARG], OPTIND=[$OPTIND] OPTARG=[$OPTARG]"
done
运行:
$ test.sh -abc ccc -e
ARG=[a], OPTIND=[1] OPTARG=[]
ARG=[b], OPTIND=[1] OPTARG=[]
ARG=[c], OPTIND=[3] OPTARG=[ccc]
ARG=[?], OPTIND=[4] OPTARG=[e]
$ test.sh -abc ccc -d
ARG=[a], OPTIND=[1] OPTARG=[]
ARG=[b], OPTIND=[1] OPTARG=[]
ARG=[c], OPTIND=[3] OPTARG=[ccc]
ARG=[:], OPTIND=[4] OPTARG=[d]
这里就不会打印出错误信息了,但是用户程序还是能够继续处理这种场景的。
- 对于不支持的参数,返回ARG是一个问号(
?
),并且OPTARG包含不支持的参数名。 - 对于缺失参数值的参数,返回ARG是一个冒号(
:
),并且OPTARG包含此的参数名。
一个比较完整的例子:
while getopts ":abc:d:" opt; do
case ${opt} in
a ) echo "opt=$opt" ;;
b ) echo "opt=$opt" ;;
c ) echo "opt=$opt,value=$OPTARG" ;;
d ) echo "opt=$opt,value=$OPTARG" ;;
: ) echo "Invalid option: $OPTARG requires an argument" 1>&2 ;;
\? ) echo "Invalid option: $OPTARG" 1>&2 ;;
esac
done
shift $((OPTIND -1))
echo "positional args=[$@]"
网友评论