文档章节

getopts简易教程(Small getopts tutorial)译文

Feng_Yu
 Feng_Yu
发布于 2015/01/31 18:18
字数 2540
阅读 540
收藏 0

getopts简易教程

当你想用一种专业的方式解析命令行参数时,getopts就是要选择的工具。和它的旧版本兄弟命令getopt不同(注意没有s!),getopts是shell内置命令。高级地方表现在

  • 你不需要通过一个外部命令传递参数
  • getopts可以很容易的设置一些你能用于解析参数的变量(对于一个外部程序来说这是不可能的!)
  • 你不必再处理过去一些使用getopt时的一些bug实现(空格, …)
  • getopts已经在POSIX®定义

一些解析位置参数的其他方法(不用getopt(s))在这里介绍了: 如何处理位置参数.

注意getopts不能解析GNU风格的长选项(--myoption)或XF86风格的长选项(-myoption)!

介绍

术语

需要先了解一下我们这里探讨的事情,所以让我们来看一个范例… 来看一下下面这行命令:

mybackup -x -f /etc/mybackup.conf -r ./foo.txt ./bar.txt

所有这些都叫位置参数,但是你可以把他们分成一些逻辑组:

  • -x是一个选项, 一个标识, 一个开关: 一个字符, 有一个前引导短横杠(-)
  • -f也是一个选项,但是这个选项有一个附加参数(传递给-f选项的参数): /etc/mybackup.conf。这个参数通常与它的参数分开(使用一个空格或其他分隔符), 但这不是必须的, -f/etc/mybackup.conf也是合法的。
  • -r依赖于配置。在这个范例中,-r不需要参数,所以它是独立的选项,像-x
  • ./foo.txt和./bar.txt是剩余的参数,不与任何选项关联。这些通常用作聚合参数(比如你指定给cp(1)的文件名)或者不需要选项的参数,因为这是程序的预定义格式(就像你传递给文本编辑器的文件名参数,用于打开和显示文本 - 为何还需要一个额外的开关呢?). POSIX®调用它们作为操作对象

让你体会一下为什么getopts很有用: 上面的命令可以像这样读取…

mybackup -xrf /etc/mybackup.conf ./foo.txt ./bar.txt

…使用自己的代码去解析很困难。而getopts可以认出所有常见的选项格式。

选项标识可以有大小写,也可以是数字。甚至是其他可识别字符,但是并不推荐这么做(可用性差而且特殊字符可能会出问题)。

原理

一般你需要调用getopts好几次。每次会使用"下一个"位置参数(和一个可能的附加参数),如果解析成功,会给你返回结果。getopts不会改变位置参数的设定 —— 如果你想要shift掉参数,你必须手工处理:

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

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 optionVARNAME is set to ? (quersion-mark) and OPTARG is unset
required argument not foundVARNAME is set to ? (quersion-mark), OPTARG is unset and an error message is printed

安静模式

选项说明
invalid optionVARNAME is set to ? (question-mark) and OPTARG is set to the (invalid) option character
required argument not foundVARNAME 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!
$ 

最后一个例子让我们需要考虑到几点:

  • 无效选项并不停止处理过程: 如果你想停掉脚本,你必须自己处理(在正确位置退出)
  • 多个相同选项是可行的: 如果你你不允许这么做,你必须自己检测(例如,设置一个变量或其他方式)

一个带参数的选项

让我们把上面的例子扩展一下。只有一点点:

  • -a现在需要一个参数-a now takes an argument
  • 遇到错误,解析过程以exit 1退出
#!/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
$

参考资料

© 著作权归作者所有

共有 人打赏支持
Feng_Yu
粉丝 157
博文 38
码字总数 45571
作品 0
西安
运维
私信 提问
bash/shell 解析命令行参数工具:getopts/getopt

bash 脚本中,简单点的参数选项,我们可以直接用位置参数 $1 $2 这样来获取处理了,例如下面这段代码片段: optionParam=$1baseHdfsPath=$2echo $optionParam|grep -qE '^(-d|-l)$' || usage...

大数据之路
2014/02/23
0
1
getopts 处理shell脚本参数

intruduction   shell 脚本有二种方法定位脚本参数,一种是使用位置变量,二是使用getopts。使用位置参数有两个限制,他需要编程者自己测试错误并建立相应的消息。若使用shift处理参数,s...

adelphos
2014/11/07
0
0
shell中getopt/getopts的使用

getopts配合case来进行操作时有两个隐含变量:一个是OPTARG,用来取当前选项的值,另外一个是OPTIND,代表当前选项在参数列表中的位移。OPTIND是一个特殊的变量,它的初始值是1,每次getopts...

拜仁慕尼黑
2013/03/22
0
0
shell脚本使用getopts自定义传入参数选项

使用getopts,示例如下: 在以上示例中, 1、执行 运行结果为 -h is set 2、执行如下 结果为 -s=sort -h is set 重要信息: getopts后面的字符串就是可以使用的选项列表,每个字母代表一个选...

HillYoung
2016/10/23
264
0
shell 中getopts 的应用

该语句的格式为: getopts一般格式为: getopts optionstring variable 其中optionstring中包含一个有效的单字符选项。若getopts命令在命令行中发现了连字符,那么它将用连字符后面的字符同 ...

月黑风高杀人夜
2015/08/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

域名备案图文教程

摘要: 备案不易,且行且珍惜! 我买了个腾讯云的服务器,1核1G,打算用于部署个人网站kiwenlau.com。根据规定,在国内部署网站,是需要为域名备案的... 备案是通过腾讯云申请的,一切都很顺利...

Fundebug
2分钟前
0
0
怎么写出好的敏捷测试(Agile Tesing)策略文档

敏捷测试策略 在敏捷环境中,我们在短期冲刺或迭代中工作,每个sprint只关注一些需求或用户故事,因此文档在数量和内容方面可能不会那么广泛。 之前我们得出的结论是,由于时间限制,我们可能...

程序猿拿Q
2分钟前
0
0
Linux之《荒岛余生》(二)CPU篇

Linux之《荒岛余生》(二)CPU篇 温馨提示,动图已压缩,流量党放心查看。CPU方面内容不多,我们顺便学点命令。本篇是《荒岛余生》系列第二篇,垂直观测CPU。其余参见: Linux之《荒岛余生》...

小姐姐味道
6分钟前
0
0
DRDS SQL 审计与分析——全面洞察 SQL 之利器

背景 数据库存储着系统的核心数据,其安全方面的问题在传统环境中已经成为泄漏和被篡改的重要根源。而在云端,数据库所面临的威胁被进一步的放大。因此,对云数据库的操作行为尤其是全量 SQ...

阿里云云栖社区
7分钟前
2
0
JSONArray 排序

List<JSONObject> jsonArySort = new ArrayList<JSONObject>();    for (int i = 0; i < rtJsonArray.length(); i++) {    jsonArySort.add(rtJsonArray.getJSONObject(i));......

MoksMo
10分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部