选项处理(二)使用 getopts 处理多命令行选项

getopts 的优势:

  • 我们不需要通过外部程序来处理位置参数;
  • getopts 可以容易地设置我们可以用来解析的 Shell 变量(这对于一个外部进程是不可能的);
  • getopts 定义在 POSIX 中。

比如,有如下的调用:

mybackup.sh -x -f /etc/mybackup/conf -r ./source.txt ./destination.txt

我们可以将上述这些选项和参数划分为如下所示的逻辑组:

  • -x、-r 都是一个单独的选项,后面不跟参数;
  • -f 也是一个选项,但是这个选项有一个附带的参数 /etc/mybackup.conf。这个参数通常与选项之间用空格分隔;
  • ./source.txt 和 ./destination.txt 是不与任何选项关联的两个参数。

如果我们在脚本 mybackup.sh 中使用了 getopts 来处理命令行选项和参数,那么上述命令还可以写为:

mybackup.sh -xrf /etc/mybackup/conf ./source.txt ./destination.txt

getopts 会识别所有这些选项格式,指定的选项可以是大写或小写字母,或是数字。虽然它也能识别其他字符,但是不推荐使用。

通常情况下,在处理命令行选项和参数时,我们需要多次调用 getopts。getopts 本身不会更改位置参数的设置,如果我们想要将位置参数移位,必须仍使用 shift 命令来处理位置参数。

因为当没有内容可以解析时,getopts 会设置一个退出状态 FALSE,所以它很容易在 while 循环中使用:

while getopts ...; do
...
done

getopts 将解析选项和它们可能的参数。它将在第一个非选项参数(不以连字符“-”开头的,且不是它前面的任何选项的参数的字符串)的位置停止解析。当遇到双连字符“--”(表示选项的结束)时,它也将停止解析。

getopts 会使用到如下 3 个变量:

  • OPTIND:存放下一个要处理的参数的索引。这是 getopts 在调用过程中记住自己状态的方式。同样可以用于移位使用 getopts 处理后的位置参数。OPTIND 初始被设置为 1,并且如果你想再次使用 getopts 解析任何内容,都需要将其重置为 1;
  • OPTARG:这个变量被设置为由 getopts 找到的选项所对应的参数;
  • OPTERR:它的值为 0 或者 1。指示 Bash 是否应该显示由 getopts 产生的错误信息。在每个 Shell 启动时,它的值都被初始化为 1。如果我们不想看到烦人的信息,可以将它的值设置为 0。

getopts 命令的基本语法:

getopts OPTSTRING VARNAME [ARGS...]
  • OPTSTRING:告诉 getopts 会有哪些选项和在哪会有参数;
  • VARNAME:告诉 getopts 哪个变量用于选项报告;
  • ARGS:告诉 getopts 解析这些可选的参数,而不是位置参数。

例如,如下的命令告诉 getopts 查找 -f、-A 和 -x 选项:

getopts fAx VARNAME

而下面的命令告诉 getopts -A 选项后面会有一个参数:

getopts fA:x VARNAME

默认情况下 getopts 命令是解析当前 Shell 或函数的位置参数。我们可以指定自己的参数让 getopts 来解析。一旦额外的参数指定在了 VARNAME 之后,getopts 将不再尝试解析位置参数,而是解析这些额外指定的参数。

getopts 命令还支持两种错误报告的模式,分别为:详细错误报告模式和抑制错误报告模式。对于产品中的脚本,推荐使用抑制错误报告模式,因为这样看起来更专业,不会看到恼人的标准信息。同样它也更容易处理,因为我们以更简单的方法显示了失败的情况。

在详细错误报告模式下,如果 getopts 遇到了一个无效的选项,VARNAME 的值会被设置为问号(?),并且变量 OPTARG 不会被设置;如果需要的参数没有找到,VARNAME 的值同样会被设置为问号(?),变量 OPTARG 也不会被设置,并且会打印一个错误信息。

在抑制错误报告模式下,如果 getopts 遇到了一个无效的选项,VARNAME 的值会被设置为问号(?),并且变量 OPTARG 会被设置为选项字符;如果需要的参数没找到,VARNAME 的值同样会被设置为冒号(:),并且变量 OPTARG 中会包含选项字符。

实例1

#! /bin/bash

# 这里仅解析 -a 选项,选项字符串中的第一个字符为冒号(:),表示抑制错误报告
while getopts ":a" opt
do
        case $opt in
                # 匹配 -a 选项
                a)
                        echo "The option -a was triggered!"
                        ;;
                # 匹配其他选项
                \?)
                        echo "Invalid option: -${OPTARG}"
                        ;;
        esac
done

使用效果:

显示效果

以上的操作中,我们可以发现:

  • 无效的选项不会停止处理:如果我们希望脚本在这种情况下停止运行,我们必须自己做一些完善操作(在适当的位置执行 exit 命令);
  • 多个相同的选项是可能的:如果你想禁止重复的选项,你必须在脚本中做一些检查操作。

实例2

#! /bin/bash

vflag=off
filename=""
output=""

function usage() {
        echo "USAGE:"
        echo "  myscript [-h] [-v] [-f <filename>] [-o <filename>]"
        exit 1
}

# 在 while 循环中使用 getopts 解析命令行选项
# 要解析的选项有 -h、-v、-f 和 -o,其中 -f 和 -o 选项带有参数
# 字符串选项中第一个冒号表示 getopts 使用抑制错误报告模式

while getopts :hvf:o: opt
do
        case "$opt" in
                v)
                        vflag=on
                        ;;
                f)
                        filename=$OPTARG
                        if [ ! -f $filename ]
                        then
                                echo "The source file $filename doesn't exist!"
                                exit
                        fi
                        ;;
                o)
                        output=$OPTARG
                        if [ ! -d `dirname $output` ]
                        then
                                echo "The output path `dirname $output` doesn't exist!"
                                exit
                        fi
                        ;;
                h)
                        usage
                        exit
                        ;;
                :)
                        echo "The option -$OPTARG requires an argument."
                        exit 1
                        ;;
                ?)
                        echo "Invalid option: -$OPTARG"
                        usage
                        exit 2
                        ;;
        esac
done

上述示例的运行效果如下:

显示效果

本文参考自 《Linux Shell命令行及脚本编程实例详解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,599评论 18 139
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,134评论 2 34
  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,156评论 9 467
  • 对于专业人士来说,熊猫烧香病毒曾经也只是菜鸟级别程序,而就是这种在专业人士里眼里非常普通的病毒程序,在当年却让近百...
    科技大望路阅读 750评论 0 0
  • 公然矫情 从未觉得毕业遥遥无期,但我一直在离校的前一个星期才真正感受到毕业的脚步声,没有任何的错手不及,一切...
    南妹子阅读 301评论 0 0