bash getopts教程
在本教程中,我们将学习bash或者shell编程语言中的getopts
。
getopts是get
heopt
ion的缩写,我们以脚本的标志形式提供了它。
它有一个非常具体的语法,乍一看似乎很令人困惑,但是,一旦我们全面研究了它,对于我们来说,它应该不会太复杂。
我写了另一篇文章,它可以以一种非常干净的方式编写带有多个输入参数的脚本,而无需使用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来获得更详细的输出
##代码##接下来,我们还定义密码的长度
##代码##