Shell内置命令getopts的简单用法
描述
如果想用比较专业的方式处理命令行参数,
getopts
将是一个不错的选择,它不像它的兄长getopt
(注意这个命令的结尾少一个字母s),getopts
是一个shell内置的命令,它的优势如下:
- 不需要将位置参数传递给一个外部程序(external program).
- 作为一个shell的内置命令,
getopts
可以设置shell变量用于解析位置参数(外部进程做不到这一点).- 相似功能的命令往往有许多复杂的概念.
getopts
定义在POSIX
标准中.
注意:getopts
不能够处理GNU风格的长选项(比如:--myoption
),也不能够处理XF86风格的长选项(比如:-myoption
).
术语
mybackup -x -f /etc/mybackup.conf -r ./foo.txt ./bar.txt
命令mybackup之后的字符都是位置参数,但是这些位置参数可以划分成如下一些逻辑分组:
-x
是一个选项option
(又称为标记flag
或者开关switch
),它是由一个破折号和一个单独的字符构成.-f
也是一个选项option
,但是这个选项指定了一个选项参数option argument
: /etc/mybackup.conf。将选项和它的选项参数合并为一个参数也是有效的,例如,-f/etc/maybackup.conf
-r
依赖于程序的功能,在这个例子里,-r
后面不需要接选项参数,所以它是一个独立的选项,就像-x
./foo.txt
和./bar.txt
属于保留的参数,命令中没有为它们指定选项,它们经常用于作为多参数mass-arguments
。例如cp
命令最后的几个参数,或者由于程序的功能,这些参数不需要为它们指定选项,POSIX称这些参数为操作数(operands).
为了说明为什么getopts
命令非常有用,上面的这条命令等价于如下的命令:
mybackup -xrf /etc/mybackup.conf ./foo.txt ./bar.txt
如果没有getopts
的帮助,那么上面这条命令分析起来就非常困难.
我们可以用26个英文字母中的大写字母或者小写字母来作为选项的字符表示,也可以用数字来表示选项。除此之外不推荐用其他字符来表示选项,因为可能由于编码问题,造成程序无法理解我们的选项。
常用的变量
变量 | 描述 |
---|---|
OPTIND | 用于保存下一个需要处理的参数的位置(index)。在getopts 处理完毕之后,我们也可以借助这个变量来移动位置参数,比如shift $(($OPTIND - 1)) 。OPTIND 最初的值是1,如果你在分析完选项之后想再次用getopts 来分析选项,必须将OPTIND 的值重新设为1. |
OPTARG | 用于保存属于某个选项后面的选项参数,它也可以保存未知选项的选项名 |
例一
#!/bin/bash
#这个脚本的脚本名为demo2_1.sh
langu="true"
#while的判读条件是根据OPTIND所指向的位置是否为选项,只要是选项则进入while里面,否则跳出while循环
#OPTIND的规则是:OPTIND总是存储原始$*中下一个要处理的选项位置。
#OPTIND初值为1,若遇到的选项不带选项参数,则OPTIND+=1;若遇到带选项参数的选项,则OPTIND+=2;
while getopts ':f:t:' OPT; do
# 'f:t:' 和 ':f:t:'的区别是,前面如果加了冒号的话,那么输入不匹配的选项时,脚本不会报错
# f: 表示选项f后面必须接一个选项参数,同理,t:表示选项t后面必须接一个选项参数
# 如果上面的':f:t:'改成':ft:',则表示选项f后面不需要选项参数,但是选项t后面必须接一个选项参数,并且输入的参数中若包含不匹配的选项,脚本不会报错
case $OPT in
f) SRC="$OPTARG";;
t) DEST="$OPTARG";;
?) langu="false";;
esac
done
echo "源语言: $SRC"
echo "目标语言: $DEST"
echo "状态:$langu"
#shift $(($OPTIND - 1))
#echo "单词: $*"
: << !
测试样例一:
$ bash demo2_1.sh -s -f apple -t banana
源语言: apple
目标语言: banana
状态:false
测试样例二:
$ bash demo2_1.sh -fnum.1 -tnum.2
源语言: num.1
目标语言: num.2
状态:true
测试样例三:
$ bash demo2_1.sh -t yuding -f anybody+except+me
源语言: anybody+except+me
目标语言: yuding
状态:true
测试样例四:
$ bash demo2_1.sh -f first -t second -f third
源语言: third
目标语言: second
状态:true
测试样例四:
$ bash demo2_1.sh -f hahahaha -t
源语言: hahahaha
目标语言:
状态:false
#这里需要解释一下:因为-t这个选项在程序里面定义的是必须要接一个选项参数,但是测试数据没有给-t指定选项参数,故-t实际上在case匹配的是?)。如果程序的case中有:),那么-t会匹配:),而不会匹配?),只有在没有:)时-t才会匹配?)
测试样例五:
$ bash demo2_1.sh -ft source destination
源语言: t
目标语言:
状态:true
#解释:这里程序认为,-f这个选项后面接的选项参数是字符t,然后OPTIND指向字符串source,因为字符串source不是选项,所以程序跳出while循环
!
例二
#!/bin/bash
#这个脚本的脚本名为demo2_3.sh
while getopts ':f:t:' OPT; do
case $OPT in
f) SRC="$OPTARG";;
t) DEST="$OPTARG";;
:) echo "选项 -$OPTARG 要求一个参数";;
?) echo "选项 -$OPTARG 无效";;
esac
done
echo "SRC=$SRC"
echo "DEST=$DEST"
: << !
测试样例一:
$ bash demo2_3.sh -x -f Chinese -t English
选项 -x 无效
SRC=Chinese
DEST=English
测试样例二:
$ bash demo2_3.sh -f -t
SRC=-t
DEST=
测试样例三:
$ bash demo2_3.sh -t japanese -f Chinese
SRC=Chinese
DEST=japanese
测试样例四:
$ bash demo2_3.sh -f Russian -t
选项 -t 要求一个参数
SRC=Russian
DEST=
!