![如何在 bash 脚本中混合普通参数和标记参数?](https://linux22.com/image/210545/%E5%A6%82%E4%BD%95%E5%9C%A8%20bash%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E6%B7%B7%E5%90%88%E6%99%AE%E9%80%9A%E5%8F%82%E6%95%B0%E5%92%8C%E6%A0%87%E8%AE%B0%E5%8F%82%E6%95%B0%EF%BC%9F.png)
例如,gcc 接受不带任何标志的输入文件和带有以下-o
标志的输出文件:
gcc input.c -o output.out
或者
gcc -o output.out input.c
我正在创建一个随机密码生成器 bash 脚本,用户应该能够分别使用-s
、-l
、-u
标志指定特殊字符、小写字符和大写字符的数量。他们还应该能够在没有任何标志的情况下指定密码的长度。
用法示例:
./randompassword.sh -s2 -u2 -l3 16
应表示包含 2 个特殊字符、2 个大写字符、3 个小写字符且长度为 16 的密码。
我可以getopts
像这样解析标志:
while getopts s:l:u: flag
do
case "${flag}" in
s) special=${OPTARG};;
l) lower=${OPTARG};;
u) upper=${OPTARG};;
esac
done
但是我不知道如何获取没有标志的长度参数。
我尝试使用$1
,但这个参数应该能够位于命令中的任何位置,就像 gcc 示例一样。
答案1
getopts
一旦到达非选项参数,就停止解析参数列表。也就是说,它在从左到右迭代选项参数时返回成功,然后在第一个非选项上返回失败。所以正确的用例是put options and their arguments on the command line before any non-option arguments
.
getops
然后教程会显示一个命令shift $((OPTIND - 1))
。该while
循环迭代选项参数,然后将shift
它们从位置变量中删除,将非选项参数(如果有)保留在$@
.
在代码中,使用教程中的变量:
while getopts ':s:l:u:' OPTION
do
case "${OPTION}" in
s) special=${OPTARG};;
l) lower=${OPTARG};;
u) upper=${OPTARG};;
\?) echo "$0: Error: Invalid option: -${OPTARG}" >&2; exit 1;;
:) echo "$0: Error: option -${OPTARG} requires an argument" >&2; exit 1;;
esac
done
shift $((OPTIND - 1))
# now the positional variables have the non-option arguments
echo "${1}"
对于示例命令 ( ./randompassword.sh -s2 -u2 -l3 16
),输出为16
。
:
我在 getopts 字符串中添加了一个前导,因为它为您提供了“静默错误报告”,这使您的脚本可以捕获错误并发出更友好的投诉。这就是我在语句中添加的额外两个选项的功能case
。
如果用户违反规则并键入选项参数后非选项参数,后面的选项参数不会在while
上面的循环中被解析。它/它们将出现在$@
包含剩余位置参数的数组中。如果用户遵循准则并在非选项参数之前键入所有选项参数,则在循环和命令完成$@
后数组将具有非选项参数。while
shift
根据您对非选项参数输入顺序的担忧,要么您的脚本需要严格的顺序,您的用户必须遵循该顺序(否则他们会收到错误),要么您的脚本不需要它们的特定顺序,并且必须使用其他解析方法来弄清楚如何使用它们。
但在我看来,无序的参数就是我们有选项字母的原因。其余参数是有序的,否则它们将具有选项字母。不过,这只是我的意见。