bash getopts教程

时间:2020-01-09 10:37:22  来源:igfitidea点击:

在本教程中,我们将学习bash或者shell编程语言中的getopts
getopts是getheoption的缩写,我们以脚本的标志形式提供了它。
它有一个非常具体的语法,乍一看似乎很令人困惑,但是,一旦我们全面研究了它,对于我们来说,它应该不会太复杂。

我写了另一篇文章,它可以以一种非常干净的方式编写带有多个输入参数的脚本,而无需使用getopts

getopt与getopts

" getopts"是一个内置的shell,在常规的Bourne shell(sh)和Bash中都可用。
它起源于1986年,是对1980年之前创建的getopt的替代。
与getopts相比,getopt不是内置在shell中,它是一个独立程序,已移植到许多不同的Unix中和类Unix发行版。

getopts和getopt之间的主要区别如下:

  • getopt不能很好地处理空标志参数。而 getopts处理

  • " getopts"包含在Bourne shell和Bash中; getopt需要单独安装

  • getopt允许解析长选项(--help而不是-h); getopts不允许

  • getopts具有更简单的语法; getopt更复杂(主要是因为它是一个外部程序而不是内置程序)

getopts语法

内置的" getopts"(不在tcsh中)解析命令行参数,从而使编写遵循Linux参数约定的程序更加容易。

语法为:

getopts optstring varname [arg ...]
  • 其中optstring是有效选项字母的列表,

  • varname是一次接收一个选项的变量,

  • arg是要处理的参数的可选列表。

  • 如果不存在" arg",则" getopts"将处理命令行参数。

  • 如果optstring以冒号(:)开头,则脚本必须负责生成错误消息;否则,getopts会生成错误消息。

  • 内置的" getopts"使用" OPTIND"(选项索引)和" OPTARG"(选项参数)变量来跟踪和存储与选项相关的值。

  • 当shell脚本启动时,OPTIND的值为1.

  • 每次调用" getopts"并找到一个参数时,它将" OPTIND"递增到要处理的下一个选项的索引。

  • 如果该选项带有参数,则bash将参数的值分配给OPTARG

示例1:将bash getopts与单个参数一起使用

在此示例脚本中,我们将使用getopts将单个参数作为脚本的输入。
该脚本当前仅支持-h作为输入参数,该参数将显示用法功能

# cat single_arg.sh
#!/bin/bash
function usage {
        echo "./$(basename 
# bash single_arg.sh -h
showing usage!
./single_arg.sh -h --> shows usage
) -h --> shows usage" } # list of arguments expected in the input optstring=":h" while getopts ${optstring} arg; do case ${arg} in h) echo "showing usage!" usage ;; :) echo "
# bash single_arg.sh -m
Invalid option: -m.
: Must supply an argument to -$OPTARG." >&2 exit 1 ;; ?) echo "Invalid option: -${OPTARG}." exit 2 ;; esac done

让我们了解脚本:

  • 在此版本的代码中,每次控件转移到循环顶部时,while结构都会评估内置的" getopts"。

  • 内置的getopts使用OPTIND变量来跟踪下一次被调用时要处理的参数的索引。

  • 在此示例中,没有必要调用shift。

  • 在此脚本中,大小写模式不能以连字符开头,因为arg的值只是选项字母(getopts剥离连字符)。

  • 因为我们告诉getopts哪些选项有效,哪些选项需要参数,所以它可以检测命令行中的错误并以两种方式处理它们。

  • 本示例在optstring中使用前导冒号来指定我们检查并处理代码中的错误;当getopts找到无效的选项时,它将'varname'(根据我们的语法)设置为.,并将OPTARG设置为选项字母。
    当它找到一个缺少参数的选项时,getopts将varname设置为,而将OPTARG设置为缺少参数的选项。

  • "。
    "大小写模式指定当" getopts"检测到无效选项时要采取的措施。

  • ":"案例模式指定当" getopts"检测到缺少的选项参数时要采取的措施。

  • 在这两种情况下,getopts都不会写任何错误信息,而是将任务留给我们。

  • 如果我们从optstring中省略前导冒号,则无效的选项和缺少的选项参数都将导致为varname分配字符串

  • 未设置OPTARG,而getopts将其诊断消息写入标准错误。

  • 通常,此方法不太理想,因为我们对错误发生时用户看到的内容的控制较少。

当我用-h标志执行脚本时:

# cat multi_arg.sh
#!/bin/bash
function usage {
        echo "Usage: $(basename 
# ./multi_arg.sh -a -b -c -d
Option 'a' was called
Option 'b' was called
Option 'c' was called
Option 'd' was called
All ARGS: -a -b -c -d
1st arg: -a
2nd arg: -b
3rd arg: -c
4th arg: -d
OPTIND: 5
) [-abcd]" 2>&1 echo ' -a shows a in the output' echo ' -b shows b in the output' echo ' -c shows c in the output' echo ' -d shows d in the output' exit 1 } if [[ ${#} -eq 0 ]]; then usage fi # Define list of arguments expected in the input optstring=":abcd" while getopts ${optstring} arg; do case "${arg}" in a) echo "Option 'a' was called" ;; b) echo "Option 'b' was called" ;; c) echo "Option 'c' was called" ;; d) echo "Option 'd' was called" ;; ?) echo "Invalid option: -${OPTARG}." echo usage ;; esac done # Debug output echo "All ARGS: ${@}" echo "1st arg: " echo "2nd arg: " echo "3rd arg: " echo "4th arg: " # Inspect OPTIND echo "OPTIND: $OPTIND"

同样,如果我们使用其他标志执行相同的脚本:

# ./multi_arg.sh -f
Invalid option: -f.
Usage: multi_arg.sh [-abcd]
   -a   shows a in the output
   -b   shows b in the output
   -c   shows c in the output
   -d   shows d in the output

示例2:收集多个输入参数

  • 在此示例脚本中,我们将使用getopts收集多个输入参数。

  • 我们的optstring变量包含受支持的输入参数的列表

  • 我们在optstring变量中添加了冒号(:),以便脚本本身处理任何错误。

  • 我还添加了一些DEBUG输出,以便我们可以了解如何使用getopts处理输入参数。

# ./multi_arg.sh -abcd
Option 'a' was called
Option 'b' was called
Option 'c' was called
Option 'd' was called
All ARGS: -abcd
1st arg: -abcd
2nd arg:
3rd arg:
4th arg:
OPTIND: 2

其中:我们使用所有4个受支持的选项执行脚本。
OPTIND的值为5,即4个输入参数+ 1 = 5

#!/bin/bash
# generate a random password
function usage {
        echo "Usage: $(basename 
# ./gen_pwd.sh -s
153d82f5700bc0377c3c64808e90d32d8b3e1ef5454c8d0e)
) [-vs] [-l LENGTH]" 2>&1 echo 'Generate a random password.' echo ' -l LENGTH Specify the password length' echo ' -s Append a special character to the password.' echo ' -v Increase verbosity.' exit 1 } function print_out { local MESSAGE="${@}" if [[ "${VERBOSE}" == true ]];then echo "${MESSAGE}" fi } # Set default password length LENGTH=48 # if no input argument found, exit the script with usage if [[ ${#} -eq 0 ]]; then usage fi # Define list of arguments expected in the input optstring=":svl" while getopts ${optstring} arg; do case ${arg} in v) VERBOSE='true' print_out "Verbose mode is ON" ;; l) LENGTH="${OPTARG}" ;; s) USE_SPECIAL_CHAR='true' ;; ?) echo "Invalid option: -${OPTARG}." echo usage ;; esac done print_out 'Generating a password' PASSWORD=$(date +%s%N{RANDOM${RANDOM}} | sha256sum | head -c${LENGTH}) # Append a special character if requested to do so. if [[ ${USE_SPECIAL_CHAR} == true ]];then print_out "Selecting a random special character" SPECIAL_CHAR=$(echo '!@#$%^&*()_+=' | fold -w1 | shuf | head -c1) PASSWORD="${PASSWORD}${SPECIAL_CHAR}" fi print_out 'Done' print_out 'Here is your password' # Display the password echo "${PASSWORD}" exit 0

如果我们用错误的参数执行脚本

# ./gen_pwd.sh -v
Verbose mode is ON
Generating a password
Done
Here is your password
3633292ba64968e1849c3fb927c35f0613d406406c2e02a3

我们还可以结合所有输入参数,而getopts会将它们分开并分别考虑每个字母

# ./gen_pwd.sh -v -l30
Verbose mode is ON
Generating a password
Done
Here is your password
080bf7350785f1074bb5468f0f20c3

尽管如我们所见,对于shell脚本-abcd被认为是单个参数,但是getopts拆分了输入参数并采用了单独的标志作为输入

示例3:在shell脚本中使用getopts将生成随机密码

  • 现在我们已经熟悉了bash或者shell脚本中getopts的语法和用法。
    让我们以更实际的示例为例,该示例将具有多个输入参数。

  • 在此脚本中,我们将使用" getopts"来收集输入参数,然后使用这些参数,脚本将生成一个随机密码

  • 该脚本需要输入参数,否则将无法执行

  • 我们可以使用-s将特殊字符添加到生成的密码中

  • 使用-l <length>定义密码的长度,脚本将使用的默认长度为48.

  • 使用-v增加详细程度

##代码##

现在,我们使用-s执行此脚本,以在密码后添加一个特殊字符。
由于我们未使用-v,因此输出非常简短,仅包含长度为48的密码

##代码##

这次我们使用-v来获得更详细的输出

##代码##

接下来,我们还定义密码的长度

##代码##