getopts 解析bash 命令行参数

getopts 解析bash 命令行参数

Shell脚本中的一项常见任务是解析命令行参数。 Bash提供了内置函数getopts来完成此任务。本教程说明了如何使用内置的getopts函数来解析bash脚本的参数和选项。

getopts 语法

getopts optstring name [args]

总共有三个参数:

  • optstring
    需要识别选项列表。说明哪些选项有效,以字母顺序列出。例如,字符串ht表示选项-h-t有效。
    如果字符后面跟一个 :, 表示该选项期望有一个参数,与选项以空白字符分割。
    不能作为选项字符使用

  • name
    是一个变量,用来填充要处理的选项。

  • args
    是要处理的参数和选项的列表。如果未提供,则默认为提供给应用程序($@)的参数和选项。您可以提供第三个参数,以使用getopts解析您提供的参数和选项的任何列表。

运行

每次调用的时候,getopts都会将选项【h,t等】放置在变量name中,如果不存在则将其初始化。并且将选项的索引,放置在变量OPTIND中,每次调用脚本时, OPTIND 都会初始化为1。当选项options要求参数时,getopts将参数放置在变量OPTARG。OPTIND保留最后一次调用getopts的选项的索引值,shell不会重置OPTIND的值,通常的做法是在处理循环结束时调用shift命令,从$@处删除已处理的选项。

shift $((OPTIND -1))

当处理到最后一个选项时,getopts 会返回一个大于0的值,并退出。OPTIND 会被设置为第一个无选项实参的索引值, name 会被设置为 ?。

getopts 以两种方式处理错误。如果 optsting 的第一个参数是 :, 或者 OPTERR 设置为 0, 静默错误处理,不返回信息。 OPTERR 处理优先级更高。

如果选项【option】无效,则getopts把name设置为 ?,如果错误静默处理:则找到的选项字符将放置在OPTARG中,并且不会打印错误消息;否则则会显示错误消息并 unset OPTARG。

如果要求的实参【argument】未找到, 静默处理是把: 设置为名称,把选项放在 OPTARG中,非静默处理则set name = ?,unset OPTARG, 打印错误。

如果getopts 找到 options, 不管是未定义,还是已定义的,都返回true; 如遇到错误,或到结尾,返回false。【方便循环处理options】

example

  • 在以下循环中,opt将保存由getopts解析的当前选项的值。
while getopts ":ht" opt; do
  case ${opt} in
    h ) # process option h
      ;;
    t ) # process option t
      ;;
    \? ) echo "Usage: cmd [-h] [-t]"
      ;;
  esac
done

  • 带参选项解析

本身具有参数的选项以:表示。选项的参数放置在变量OPTARG中。在下面的示例中,选项t带有一个参数。提供参数后,我们会将其值复制到变量target。如果未提供任何参数,则getopts将opt设置为:我们可以通过捕获:case并打印适当的错误消息来识别此错误情况。

while getopts ":t:" opt; do
  case ${opt} in
    t )
      target=$OPTARG
      ;;
    \? )
      echo "Invalid option: $OPTARG" 1>&2
      ;;
    : )
      echo "Invalid option: $OPTARG requires an argument" 1>&2
      ;;
  esac
done
shift $((OPTIND -1))
  • 解析嵌套的参数和选项

我们以pip 为例, 实现一个带有子命令,子选项的shell脚本。

> pip -h

Usage:
      pip <command> [options]

Commands
      install     Install a Python package.

General Options:
      -h          Show help.

首先使用getopts通过以下while循环来解析-h选项。在其中,我们使用?捕获无效的选项,并用移位$((OPTIND -1))移位所有已处理的参数。

while getopts ":h" opt; do
    case ${opt} in
        h )
            echo "Usage:"
            echo "      pip <command> [options]"
            echo ""
            echo "Commands"
            echo "      install     Install a Python package."
            echo ""
            echo "General Options:"
            echo "      -h          Show help."
            exit 0
        ;;
        \? )
            echo "Invalid Option: -$OPTARG" 1>&2
            exit 1
        ;;
    esac
done
shift $((OPTIND -1))

现在为我们的scirpt添加一个子命令install, install 把将要安装的python包作为参数

> pip install urllib3

同时 install还有一个选项t,t值作为软件安装位置

> pip install urllib3 -t ./src/lib

我们必须要找到要执行的自命令。这是我们script的第一个实参。

subcommand=$1
shift # Remove `pip` from the argument list

现在我们可以处理子命令安装。在我们的示例中,选项-t实际上是在软件包参数后面的选项,因此我们首先从参数列表中删除install并处理该行的其余部分。

case "$subcommand" in
  install)
    package=$1
    shift # Remove `install` from the argument list
    ;;
esac

在执行shfit后,剩余的参数以 package -t src/lib形式被处理。-t选项带有一个自己的实参。这个参数被存储在 OPTARG中,我们把它保存在 targe中,以待将来使用。

case "$subcommand" in
  install)
    package=$1
    shift # Remove `install` from the argument list

  while getopts ":t:" opt; do
    case ${opt} in
      t )
        target=$OPTARG
        ;;
      \? )
        echo "Invalid Option: -$OPTARG" 1>&2
        exit 1
        ;;
      : )
        echo "Invalid Option: -$OPTARG requires an argument" 1>&2
        exit 1
        ;;
    esac
  done
  shift $((OPTIND -1))
  ;;
esac

把所有的代码放在一起, 我们实现了自己的pip和 install

package=""  # Default to empty package
target=""  # Default to empty target

while getopts ":h" opt; do
    case ${opt} in
        h )
            echo "Usage:"
            echo "      pip <command> [options]"
            echo ""
            echo "Commands"
            echo "      install     Install a Python package."
            echo ""
            echo "General Options:"
            echo "      -h          Show help."
            echo "      -t          Location where the package to install"
            exit 0
        ;;
        \? )
            echo "Invalid Option: -$OPTARG" 1>&2
            exit 1
        ;;
    esac
done
shift $((OPTIND -1))  # remove options

subcommand=$1; shift  # Remove 'pip' from the argument list

echo "## $@"
echo "## $subcommand"

case "$subcommand" in
# Parse options to the install sub command
    "install")
        package=$1; shift  # Remove 'install' from the argument list

    echo "## $package"
    echo "## $@"
        # Process package options
        while getopts ":t:" opt; do
            case ${opt} in
                "t" )
                    target=$OPTARG
                    echo "install $package at $target"
                ;;
                \? )
                    echo "Invalid Option: -$OPTARG" 1>&2
                    exit 1
                ;;
                : )
                    echo "Invalid Option: -$OPTARG requires an argument" 1>&2
                    exit 1
                ;;
            esac
        done
        shift $((OPTIND -1))
    ;;
esac

名词

  • OPTIND 当前处理选项的索引值
  • OPTARG 当前处理选项的实参值
  • OPTERR 当前getopts 的错误设置
  • options 选项
  • parameters 形参 【预定的参数】
  • argument 实参【传入的参数】

参考:

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