bash getopts教程
在本教程中,我们将学习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来获得更详细的输出
##代码##接下来,我们还定义密码的长度
##代码##
