当你想用一种专业的方式解析命令行参数时,getopts就是要选择的工具。和它的旧版本兄弟命令getopt不一样(注意没有s!),getopts是shell内置命令。高级地方表如今html
一些解析位置参数的其余方法(不用getopt(s))在这里介绍了: 如何处理位置参数.算法
注意getopts不能解析GNU风格的长选项(--myoption)或XF86风格的长选项(-myoption)!shell
须要先了解一下咱们这里探讨的事情,因此让咱们来看一个范例… 来看一下下面这行命令:数组
mybackup -x -f /etc/mybackup.conf -r ./foo.txt ./bar.txt
全部这些都叫位置参数,可是你能够把他们分红一些逻辑组:bash
让你体会一下为何getopts颇有用: 上面的命令能够像这样读取…编辑器
mybackup -xrf /etc/mybackup.conf ./foo.txt ./bar.txt
…使用本身的代码去解析很困难。而getopts能够认出全部常见的选项格式。函数
选项标识能够有大小写,也能够是数字。甚至是其余可识别字符,可是并不推荐这么作(可用性差并且特殊字符可能会出问题)。工具
通常你须要调用getopts好几回。每次会使用"下一个"位置参数(和一个可能的附加参数),若是解析成功,会给你返回结果。getopts不会改变位置参数的设定 —— 若是你想要shift掉参数,你必须手工处理:oop
shift $((OPTIND-1)) # now do something with $@
由于getopts在没有要解析的参数剩余时会返回退出状态_FALSE_,因此能够很容易的在while循环使用:测试
while getopts ...; do ... done
getopts将会解析选项和他们可能的参数。遇到第一个非选项的参数时将会中止解析(一个不以连字符(-)开头的字符串,这不是前面任何一个选项的参数)。一样也会在看到--(双连字符)时中止解析,由于这个含义是选项终止。
变量 | 描述 |
---|---|
OPTIND | 保存下一个要解析的参数的指针。这就是getopts如何"记住"本身的状态和回调请求。一样能够用于在getopts处理过以后shift掉位置参数。OPTIND初始为1, 若是你想要再次使用getopts解析任何参数时须要从新设置为1 |
OPTARG | 这个变量设置为被getopts发现的选项的参数。一样包含了未知的选项标记 |
OPTERR | (可选值0或1)代表Bash是否应该显示getopts内置的错误信息。该值在每一个shell启动的时候会被初始化为1 - 因此若是你不想看到烦人的信息请务必设置为0! |
getopts一样使用这些变量用于错误报告(they're set to value-combinations which arent possible in normal operation).#括号里面的不会翻译,预留
getopts的基本语法是:
getopts OPTSTRING VARNAME [ARGS...]
解释:
选项 | 说明 |
---|---|
OPTSTRING | 告诉getopts指望哪一个选项和指望的参数在哪里(参考下面的) |
VARNAME | 告诉getopts哪一个shell变量用于选项报告 |
ARG | 告诉getopts将这些解析为附加单词而不是位置参数 |
option-string告诉getopts指望哪一个选项,而且哪一个选项必须有参数。语法很是简单 -- 每一个字母就是选项名自己,下面这个范例告诉getopts寻找-f, -A和-x:
getopts fAx VARNAME
当你想让getopts对某个选项指望一个参数时,只是在这个选项标记后面放置一个:(冒号)。若是你想让-A指望一个参数(例如变成 -A SOMETHING),只须要:
getopts fA:x VARNAME
若是option-string首个字母是:(冒号),一般是荒谬的,由于没有任何选项在它以前,这种状况下,getopts会切换到"静默错误报告"模式。在产品脚本中,这一般就是你想要的结果(自行抓取错误信息处理,不要被烦人的信息所干扰)。
getopts工具会默认解析当前shell或函数的位置参数(意味着它解析的是"$@")。
你能够给出你本身的一组参数解析。当附加参数在VARNAME参数以后给出时,getopts并不试图解析这些位置参数。
用这种方式,你能够按照你喜欢的方式解析任何选项,这里是一个数组的范例:
while getopts :f:h opt "${MY_OWN_SET[@]}"; do ... done
不带这些附加参数调用getopts的方式等同于显式的使用"$@"调用:
getopts ... "$@"
关于错误报告,getops能够在两种模式下运行:
对于产品脚本我建议使用静默模式,由于这样看起来更专业,你不想看到更多烦人的信息。一样也更容易处理,失败的用例都以更简单的方式显示。
选项 | 说明 |
---|---|
invalid option | VARNAME is set to ? (quersion-mark) and OPTARG is unset |
required argument not found | VARNAME is set to ? (quersion-mark), OPTARG is unset and an error message is printed |
选项 | 说明 |
---|---|
invalid option | VARNAME is set to ? (question-mark) and OPTARG is set to the (invalid) option character |
required argument not found | VARNAME is set to : (colon) and OPTARG contains the option-character in question |
足够说明一些问题!
让咱们先看一个很是简单的实例: 只有一个指望的选项(-a),没有任何参数。一样咱们用带:(冒号)的option string为了禁用详尽错误显示:
#!/bin/bash while getopts ":a" opt; do case $opt in a) echo "-a was triggered!" >&2 ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; esac done
我把这些内容放到一个文件go_test.sh,就是你接下来看到的范例中的名字。
来让咱们作一些测试:
$ ./go_test.sh $
什么都没发生?对的,getopts没看到任何合法或非法的选项(前面有短横线的字母),因此不会触发。
$ ./go_test.sh /etc/passwd $
仍是 — 什么都没发生。很是相似的用例: getopts没看到任何合法或非法的选项(前面有短横线的字母),因此不会触发。
传递给你的脚本的参数固然能够用$1 - ${N}获取。
如今让咱们触发一下getopts: 提供选项。
首先,来一个非法的:
$ ./go_test.sh -b Invalid option: -b $
和预期的同样,getopts不容许这个选项,像上面说的同样: It placed ? into $opt and the invalid option character (b) into $OPTARG. 咱们的用例就验证了这一点。
如今,来一个合法的(-a):
$ ./go_test.sh -a -a was triggered! $
你看到了,这个探测结果运行的很完美。在咱们的用例a选项放在了变量$opt中。
固然在调用的时候能够组合有效和无效的选项:
$ ./go_test.sh -a -x -b -c -a was triggered! Invalid option: -x Invalid option: -b Invalid option: -c $
最后,天然也能够屡次给出咱们的选项:
$ ./go_test.sh -a -a -a -a -a was triggered! -a was triggered! -a was triggered! -a was triggered! $
最后一个例子让咱们须要考虑到几点:
让咱们把上面的例子扩展一下。只有一点点:
#!/bin/bash while getopts ":a:" opt; do case $opt in a) echo "-a was triggered, Parameter: $OPTARG" >&2 ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac done
让咱们继续作和最后一个范例一样的测试:
$ ./go_test.sh $
像上面同样,什么都没发生。就没触发。
$ ./go_test.sh /etc/passwd $
很是相似的状况: 没有触发。
非法选项:
$ ./go_test.sh -b Invalid option: -b $
和指望的同样,像上面同样,getopts不容许这个选项,和程序算法吻合。
合法选项,可是不带强制要求的参数:
$ ./go_test.sh -a Option -a requires an argument. $
选项OK,可是丢掉了一个参数。
让咱们提供这个参数:
$ ./go_test.sh -a /etc/passwd -a was triggered, Parameter: /etc/passwd $