Shell脚本命令行参数解析工具:getopts

在处理bash脚本时,简单参数可以用$1、$2来处理,遇到需要分析复杂参数的时候,bash内建命令getopts就是一个不错的选择(也可以使用独立的可执行文件getopt)。

getopts是一个强大的选项解析工具,使用简单,支持选项连接(rsync -av型式),但是不支持长选项(vim --help型式)。

getopts工作方式

通常getopts被使用在while do语句中顺序解析参数。当遇到

  • 不以-开头的选项

  • --

    会异常中断解析(如果遇到--help型式的参数会按照选项-help处理)。

getopts变量

  • OPTARG:当前选项的参数值,如果选项解析失败,则存储的是未识别选项的名字。
  • OPTIND:接下来要解析的选项的位置

getopts用法

在bash中通常将getopts放在while中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
while getopts "OPTSTRING" TEMP_OPT_VAR; do
case $TEMP_OPT_VAR in
OPT1)
... ;;
OPT2)
... ;;
:) #选项需要参数,但没有读取到时
... ;;
?) #选项不能识别时
... ;;
...
esac
done

其中:

  • OPTSTRING:通过OPTSTRING可以告诉getopts哪些选项是合法的,哪些选项是需要参数的,以及遇到不能识别的参数时是否需要打印提示信息(./test.sh: option requires an argument – a)。这些功能都是通过冒号:完成的。

    • 字符串首位如果出现:则表示不打印错误信息。
    • 选项名字后的:表示该选项需要参数。

    例如:

    OPTSTRING是"​:a​:bc"时,表示不打印未识别提示信息,有a、b、c三个选项,a需要参数。

  • TEMP_OPT_VAR:暂存读取到的选项,后续case需要使用。

getopts使用实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash

while getopts ":a:bc" OPT; do
case $OPT in
a)
echo "Next pos is $OPTIND, a is arg:$OPTARG" ;;
b)
echo "Next pos is $OPTIND, b is triggered" ;;
c)
echo "Next pos is $OPTIND, c is triggered" ;;
:)
echo "Option $OPTARG needs argument" ;;
?)
echo "Unknown option $OPTARG" ;;
esac
done

在这段代码中,设置不打印未识别信息,有abc三个选项,其中a需要参数。

(1)正确使用

1
2
3
4
5
6
7
8
$ ./test.sh -b -c -a 123
Next pos is 2, b is triggered
Next pos is 3, c is triggered
Next pos is 5, a is arg:123
$ ./test.sh -a 123 -b -c
Next pos is 3, a is arg:123
Next pos is 4, b is triggered
Next pos is 5, c is triggered

在第一次执行时,先读取b,此时OPTIND的值为2,表示接下来要读取第2个,也就是c。当读取a并且读取了a的值123后,OPTIND值为5,此时就可以结束解析过程了。

(2)选项不合法

1
2
$ ./test.sh -d
Unknown option d

(3)选项合法,缺少参数

1
2
$ ./test.sh -a
Option a needs argument

(4)选项、参数合法,读取顺序错误

1
2
3
4
5
6
$ ./test.sh -bca 123
Next pos is 1, b is triggered
Next pos is 1, c is triggered
Next pos is 3, a is arg:123
$ ./test.sh -bac 123
Next pos is 1, b is triggered

在这一组中,观察到读取完b和c,OPTIND的值并没有变化,说明bash中OPTIND的增加是以空格为分隔符计算的,并不是选项的个数。

(5)使用--的情况

1
2
3
4
$ ./test.sh --bc
Unknown option -
Next pos is 1, b is triggered
Next pos is 2, c is triggered

由此可见,使用--接选项时,除了第一个-,后续的字符都会被解析。

参考: