【问题标题】:How to validate the number of arguments (mandatory and optional) in a shell script?如何验证 shell 脚本中的参数数量(强制和可选)?
【发布时间】:2017-11-16 17:08:13
【问题描述】:

我无法验证我的脚本参数。我正在尝试为我的脚本实现 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 = "$1"
echo MP2 = "$2"
echo MP3 = "$3"
echo MP4 = "$4"
echo MP5 = "$5"

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.

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

如何正确验证此内容?

【问题讨论】:

  • -a 和 -c 选项(及其参数)可以出现在参数列表中的任何位置,还是必须出现在 5 个必需的非选项参数之后?
  • 让我在这里贪吃。假设它可以在任何地方。你有什么建议?

标签: linux bash shell getopts


【解决方案1】:

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

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

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

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

所以如果你想使用getopts风格的可选参数,你需要把它们放在参数列表的首位。解析它们时,您需要解析并从参数列表中删除*它们(使用shift检查位置参数的数量,并使用$1 等访问位置参数.您当前的脚本遇到了麻烦,因为它试图首先处理位置参数,而这不适用于 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 = $1"
echo "MP2 = $2"
echo "MP3 = $3"
echo "MP4 = $4"
echo "MP5 = $5"

if [ -n "$6" ]; then
    # This will run if a sixth argument was specified AND it wasn't blank.
    export CHAR_SET=$6
    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=$7
    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 命令的变幻莫测的风险,您可以花费大量时间和精力编写自己的解析系统。 IMO 这比它的价值要多得多。

【讨论】:

    【解决方案2】:

    每个空格分隔的字符串都会被 shell 解释为一个新的参数。您是否允许使用不带参数的 -a 标志或 -c 参数?假设那些需要在它们之后有一些东西,你实际上需要允许 5 或 7 或 9 个参数。 Getopts 与初始的 shell 参数解析是分开的。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-24
      • 2012-05-05
      • 2013-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多