getopts
是一个Bash built-in,可以用它来实现与getopt(3)
一致的参数解析功能。
注意它和getopt(1)
的区别。getopt
是一个单独的命令,而getopts
是bash内置命令。
关于option与argument的区别,我这里实在给不出准确的定义,只能根据自己的理解试着解释一下。
argument是通常所说的命令行参数,在C语言里就是argv数组,根据参数出现的顺序从argv[1]开始依次递增(argv[0]里是被执行的程序本身的程序名)。在Bash里,$0表示脚本的名称,$1开始往后是各个argument。
option有点混乱。我的理解是:一个Option是以-
(hyphen-minus character)或--
开头的字符串,它后面有可选的argument,如果有则只有一个。也就是说,一个option由一个或两个argument组成
根据上面的描述命令行参数(Arguments)可以分为3类(抱歉我这里会用比较山寨的方法来描述这三类,如果有对应的标准名称,请留言指出)
- Option with an argument:例如wget的-O选项,必须要指定一个路径或文件名作为参数
- Option without an argument:看到网上有的地方也称为switcher,开关选项。例如wget的-v和-q选项,可以使程序输出信息为verbose(详尽)或quiet(安静)
- Non-option argument:其实根据上面的描述,这个第三类有点尴尬:它不符合我定义的Option。例子就是wget命令指定文件的URL,它的前面并没有对应的-开头的字符串。
getopts的基本用法类似下面的例子:
#!/bin/bash while getopts :s:h opt do case $opt in s) echo "-s=$OPTARG" ;; :) echo "-$OPTARG needs an argument" ;; h) echo "-h is set" ;; *) echo "-$opt not recognized" ;; esac done
这个例子中,定义了一个optstring
(:s:h
)。其中第一个:
字符,打开了getopts的silent模式,可以自行对未识别的选项进行处理而不是让getopts自己报错。随后的s:
定义了一个带参数的选项,如果-s
使用时没有带上对应的argument则可以在随后的case语句中做相应的报错处理。最后的h
定义了一个不带参数的选项。getopts的使用基本就是这样了,更详尽的getopts的optstring的定义和使用请参考bash(1)
上面的例子里我没有给出如何解析非选项参数(Non-option argument)。如果我执行./test.sh -s test_string -h filename
,那么仅靠getopts
是无法获取到filename这个字符串的。
仔细阅读bash(1)
之后就会发现,getopts在访问到第一个non-option argument的时候即会停止解析,并设置$OPTIND
为第一个non-option argument在$@
中的指针。例如上面这个./test.sh -s test_string -h filename
例子,getopts解析完之后会将$OPTIND
设置为4。
结合$OPTIND
变量和shift
这个bash built-in,可以写出一个完整的解析所有参数的脚本。以下是一个例子,已经有恰当的注释信息,应该不需要额外解释了。:
#!/bin/bash declare -a NOA # Array used to store non-option argument while [ $# -ne 0 ] do # if OPTIND > $#+1, getopts will not change OPTIND's value,so set it to 0 OPTIND=0 while getopts :s: opt do case $opt in s) echo "-s=$OPTARG" ;; \?) echo "-$OPTARG not recognized" ;; esac done # if getopts find a non-option argument # it will stop parsing and return OPTIND # as index to the first non-option argument # # if getopts doesn't find any non-option argument # it will set OPTIND=$#+1 if [ $OPTIND -ne $(($#+1)) ] then shift $(($OPTIND-1)) # This is just my favorate way to append element to an array in shell. # Feel free to change it NOA=(`echo ${NOA[*]}` $1) shift else break; # getopts doesn't find any non-option argument fi done echo ${NOA[*]}
Comments !