美文网首页Shell 脚本成长笔记
选项处理(二)使用 getopts 处理多命令行选项

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

作者: 赵者也 | 来源:发表于2017-05-04 22:20 被阅读895次

    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命令行及脚本编程实例详解

    相关文章

      网友评论

        本文标题:选项处理(二)使用 getopts 处理多命令行选项

        本文链接:https://www.haomeiwen.com/subject/ptrrtxtx.html