getopts(1) builtin command

2024-09-02 08:04:22 浏览数 (2)

0.背景

在执行 Shell 脚本时,可以像运行应用程序一样传入相应的参数,在脚本内部根据传入的参数内容执行对应的操作。

Shell 脚本中可以通过1...N形式的符号来引用传入的参数,0表示当前脚本的名称。1~N 和传入参数位置相对应,比如1表示执行脚本时传入的第一个参数,2表示传入的第二个参数,以此类推引用其他参数。对于一些只需要很简单的命令行参数的脚本,通过使用N形式轻松的完成解析,但对于比较复杂的命令行形式的参数,就需要脚本的编写者在脚本中加入复杂的代码对命令行入参进行解析。

为了减少重复性编程和简化命令行参数处理的过程,Shell 为脚本编写者提供了一些命令行处理方法,使用这些方法可以轻松的处理各种形式的命令行参数。

常用的是 getopts 和 getopt。getopts 是 Shell 内建命令,getopt 是一个独立的外部命令,通常在 GNU coreutils 中提供。

本文将介绍如何使用 getopts 处理命令行参数。

1.简介

getopts 是 Shell 内建命令,用于解析位置参数。

getopts 是一个简化版的 getopt,出现的目的仅仅是为了代替 getopt 较快捷方便的执行参数分析。

getopts 语法相对简单,不支持长选项(以 -- 开头的长选项,如--help)。如果遇到非选项(非 -开头)参数就终止解析,后面的选项和参数将不会被解析。

2.格式

代码语言:javascript复制
getopts OPTSTRING NAME [ARGS]

OPTSTRING 表示要识别的命令行选项。如果一个字母后面有一个冒号 :,表示该命令行选项后面要跟一个参数。如 OPTSTRING 写成 “co:f:”,表示支持 -c、-o、-f 选项,-o 和 -f 选项后面需要跟一个参数。

NAME 为用来存储选项字符的变量名。

如果遇到一个无效选项,getopts 将选项变量 NAME 置为 ?。如果不是静默模式,则打印错误消息,并将 OPTARG 变量置空(unset)。如果是静默模式,无效选项字符将存储在 OPTARG 变量中,且不会打印任何错误消息。

如果没有找到所需的参数,并且 getopts 为非静默模式,则在 NAME 中放置一个问号,将 OPTARG 变量置空(unset),并打印错误信息。如果 getopts 为静默模式,则在 NAME 中放置冒号,并将 OPTARG 设置为找到的选项字符。

getopts 默认为非静默模式。可以在 OPTSTRING 的开头加一个冒号或将变量 OPTERR 设置为 0 开启静默模式。

ARGS 表示要解析的参数。在 Shell 脚本中使用时,默认解析的是执行 Shell 脚本传入的参数,所以这个部分可省略不写。

3.选项

无。

4.返回值

如果找到指定或未指定的选项,getopts 将返回 true。如果遇到选项结束或发生错误,则返回 false。

5.特殊变量

getopts 的使用涉及一些特殊变量。

  • OPTARG

OPTARG 存储当前选项的参数值。如果选项需要一个参数,getopts 会将该参数存储在 OPTARG 中。

  • OPTIND

OPTIND 是 getopts 内建变量,用于表示下一个要处理的参数的索引位置,从 1 开始。getopts 处理选项时会自动更新 OPTIND。

OPTIND 可用于检查和处理未解析的命令行参数。例如shift $((OPTIND -1))可以跳过已处理的选项,处理剩余的参数。

6.示例

使用 getopts,编写一个 Shell 脚本,可支持识别命令行选项 -b、-o、-h。其中,-b 和 -o 选项后需要跟一个参数。

代码语言:javascript复制
#!/bin/bash

while getopts ":a:b:h" opt_name
do
    case $opt_name in
        a) echo "-a Option is recognized, argument=$OPTARG"
           ;;
        b) echo "-b Option is recognized, argument=$OPTARG"
           ;;
        h) echo "-h Option is recognized"
           ;;
        ?) echo "Invalid option: -$OPTARG"
           exit 1
           ;;
        :) echo "-$OPTARG Option need a argument"
        exit 1
      ;;
    esac
done

shift $((OPTIND - 1))
echo "Remaining arguments: $@"

OPTSTRING 为 :b:o:h,开头的冒号,表示 getopts 以静默模式运行。

-b 和 -o 选项后跟冒号,表示需要参数。

-h 后面没有冒号,表示无需参数。

如果存储选项字符的变量 opt_name 为问号,表示遇到一个无效选项。选项字符会放置到 OPTARG 变量。

如果存储选项字符的变量 opt_name 为冒号,表示选项需要参数但没有给定参数。选项字符会放置到 OPTARG 变量。

shift ((OPTIND - 1)) 表示将已经解析的位置参数移除,使用 @ 可以访问剩余的所有参数。

运行上面的脚本会有如下输出:

代码语言:javascript复制
./getopts.sh -a valuea -b valueb -h file1 file2
-a Option is recognized, argument=valuea
-b Option is recognized, argument=valueb
-h Option is recognized
Remaining arguments: file1 file2

如果输入非法选项:

代码语言:javascript复制
./getopts.sh -c
Invalid option: -c

如果输入选项未带参数:

代码语言:javascript复制
 ./getopts.sh -a
Invalid option: -a

预期是走到 :) 分支,并输出:

代码语言:javascript复制
-a Option need a argument

实际结果与 bash manual 描述不一致,不知为何。

参考文献

bash(1) - Linux manual page Coreutils - GNU core utilities GNU Coreutils Manual - gnu.org

0 人点赞