如何验证 shell 脚本中的参数数量(强制和可选)?

How to validate the number of arguments (mandatory and optional) in a shell script?

我无法验证我的脚本参数。我正在尝试为我的脚本实现 5 个强制参数和 2 个可选参数。这是我到目前为止尝试过的方法。

#!/bin/sh

if [ $# -lt 5 ] || [ $# -gt 7 ]
then
  echo "Please supply 5 or 6 or 7 parameters. Aborting."
  exit 1
fi

echo MP1 = ""
echo MP2 = ""
echo MP3 = ""
echo MP4 = ""
echo MP5 = ""

while getopts c:a: optionalargs
do
        case $optionalargs in
          c)copt=$OPTARG;;
          a)aopt=$OPTARG;;
          *)echo "Invalid arg";;
        esac
done

if [ ! -z "$copt" ]
then
    export CHAR_SET=$copt
fi

if [ ! -z "$aopt" ]
then
    export ADDITIONAL_FLAGS=$aopt
fi

shift $((OPTIND -1))

echo OP_C = "${CHAR_SET}"
echo OP_A = "${ADDITIONAL_FLAGS}"

问题是验证此脚本的参数总数,因为我总共可以有 5 或 7 个参数。提供 -a additional -c character 被视为 9 个参数。

./a.sh 1 2 3 4 5 -a additional -c character
Please supply 5 or 6 or 7 parameters. Aborting.

我对没有 - 的设计持开放态度,只要我能够同时拥有强制参数和可选参数。

如何正确验证?

每个 space 分隔的字符串都将被 shell 解释为一个新参数。是否允许使用 -a 标志或不带参数的 -c 参数?假设那些需要跟随它们的东西,你实际上需要允许 5 或 7 或 9 个参数。 Getopts 独立于初始 shell 参数解析。

除此之外,脚本看起来不错。对于质量检查,我建议 Shellcheck

首先:shell 对可选参数和强制参数一无所知,不会特别处理以“-”开头的参数,诸如此类。它只有一个 "words" 的列表,由您的脚本来弄清楚它们的含义。 getopts 命令可以帮助解析参数,但它处理的语法相当有限:

  • 选项以单个破折号开头,并且是单个字母(可能后面有一个参数)。对于不带参数的选项,您可以在单个破折号上堆叠多个选项(例如 ls -la)。
  • 在所有选项之后,可以有许多位置参数(这些参数的含义——顾名思义——根据它们在列表中的位置定义,例如第一、第二等)。

getopts支持许多语法扩展(主要是 GNU 约定):

  • 将选项放在位置参数之后(例如 ls filename -l)。选项必须始终放在第一位。
  • 长选项(多字母 and/or 双破折号,例如 ls --all)。
  • 使用--将选项与位置参数分开。

所以如果你想使用getopts风格的可选参数,你需要把它们放在参数列表的第一位。并且在解析它们时,您需要解析并从参数列表中删除*它们(使用shift之前检查位置参数的数量,并使用</code> 等访问位置参数。您当前的脚本 运行 遇到了麻烦,因为它首先尝试处理位置参数,而这不适用于 <code>getopts(至少在没有一些繁重的 kluging 的情况下)。

如果您需要更通用的参数语法,您可以使用 getopt(注意名称中缺少 "s")。 getopt 的某些版本支持 GNU 约定,有些则不支持。有些还有其他问题。 IMO 这是一罐蠕虫,最好不要打开。

另一种可能是放弃-选项语法,并给脚本7个位置参数,其中最后两个可以省略。这样做的问题是您不能省略第六个而忽略第七个(除非您愿意将第六个留空视为等同于省略它)。代码看起来像这样:

if [ $# -lt 5 ] || [ $# -gt 7 ]
then
  echo "Please supply 5 or 6 or 7 parameters. Aborting."
  exit 1
fi

echo "MP1 = "
echo "MP2 = "
echo "MP3 = "
echo "MP4 = "
echo "MP5 = "

if [ -n "" ]; then
    # This will run if a sixth argument was specified AND it wasn't blank.
    export CHAR_SET=
    echo "OP_C = ${CHAR_SET}"
fi

if [ $# -ge 7 ]; then
    # This will run if a seventh argument was specified EVEN IF it was blank.
    # If you want to omit this for a blank arg, use the `-n` test instead.
    export ADDITIONAL_FLAGS=
    echo "OP_A = ${ADDITIONAL_FLAGS}"
fi

...然后 运行 脚本,例如

./a.sh 1 2 3 4 5 character additional    # Both optional args supplied
./a.sh 1 2 3 4 5 character               # Only first optional arg supplied
./a.sh 1 2 3 4 5 "" additional           # Only second optional arg supplied

或者,如果您真的想要更扩展的语法并且不想冒险使用 getopt 命令的变幻莫测,您可以花费大量时间和精力编写自己的解析系统。在我看来,这比它的价值要多得多。