bash 中的 getopts,脚本之前运行正常,现在我感到困惑

getopts in bash, script was working before and now I'm baffled

所以我的 bash 脚本中有几个 getopts。这是一个工作示例。

FOUND=
SEARCH=
COUNT=0
while getopts "ips:flenkc" OPTION
do
case $OPTION in
        i)
                FOUND=1
                let "COUNT++"
                ;;
        p)
                FOUND=2
                let "COUNT++"
                ;;
        s)
                FOUND=3
                SEARCH=$OPTARG
                let "COUNT++"
                ;;
esac
done

稍后检查 count=1 的 case 语句(意思是,在调用中仅使用以下 i、p 和 s 之一)不重要,除了它确定主要操作是完成。

现在有问题的是 getopts。这以前是有效的,现在不是了。目标是让如果有人想输入数据,他们可以使用以下 bash 命令。

./programname -i -f Mary -l Sue -e smary@email.com -n 555-555-5555

其中,当使用 -i 时,我们必须有 -f、-l、-e 和 -n(用于名字、姓氏、电子邮件和电话号码)。 我使用的代码:警告,代码中充满了语法错误。如果您正在学习 bash,我强烈建议您不要使用您在我的 post.

中看到的任何内容
if [ $FOUND == "1" ]
then
        echo "You have chosen to insert things."
        FIRST=
        LAST=
        EMAIL=
        NUMBER=
        while getopts "if:l:e:n:" OPTION
        do
        case $OPTION in
                f)
                        FIRST=$OPTARG
                        ;;
                l)
                        LAST=$OPTARG
                        ;;
                e)
                        EMAIL=$OPTARG
                        ;;
                n)
                        NUMBER=$OPTARG
                        ;;
        esac
        done

        if [[ -z $FIRST ]] || [[ -z $LAST ]] || [[ -z $EMAIL ]] || [[ -z $NUMBER ]]
            echo "Error!!! Some input is missing!!!"
            usage // display usage
        exit 1
        fi
        echo -e $FIRST"\t"$LAST"\t"$EMAIL"\t"$NUMBER >> contacts
fi

在此程序运行之前,但现在,甚至没有任何东西可以输入 FIRST、LAST、EMAIL 和 NUMBER(在我尝试更改代码以查看它是否使它成为某些步骤)。

我对 getopts 做错了什么?之前还可以,现在……完全不行了!

有一件事值得注意:如果您的脚本已经调用了一次 getopts,另一个 getopts 调用将在所有选项之后开始,因此实际上什么都不做;在每个后续 getopts 调用之前将 OPTIND 重置为 1 以让他们重新处理所有选项。

您的代码有两个语法错误,总体上值得清理:

  • if [[ -z ... 语句缺少 then
  • usage 之后的 // 会导致语法错误 - POSIX-like shells 使用 # 作为注释字符。
  • 因为这是 bash 脚本,坚持使用 [[ ... ]] 一贯的(不需要 [ ... ]) and/or 使用 (( ... )) 进行算术运算。
    • 具体来说,避免使用 [ ... == ... ],因为它混合了 POSIX 语法 - [ ... ] - 与 Bash 特定的语法 - == ( POSIX 只支持 =).
    • 如果您确实使用 [ ... ],请务必将变量引用用双引号引起来,以确保安全。
  • 无需多个 [[ ... ]] 表达式将它们组合在一起 - 在 单个 [[ ... || ... || ... ]].
  • 中执行
  • 最好避免全大写的 shell 变量名,以便 avoid conflicts with environment variables and special shell variables.
  • 使用 >&2.
  • 将错误消息输出到 stderr
  • 用双引号将 整个 参数括在 echo -e 中,以保护变量值免受可能不需要的扩展。

通常可以使用 shellcheck.net.

捕获单纯的语法错误

将它们放在一起,我们得到:

#!/usr/bin/env bash

# ... code that sets $found

# If you've already processed args. with getopts above,
# you must reset OPTIND to process them again.
OPTIND=1

if (( found == 1 )) # found is numeric, use arithmetic expression to compare
then
        echo "You have chosen to insert things."
        first= last= email= number= # don't use all-uppercase var. names
        while getopts "if:l:e:n:" option
        do
          case $option in
                f)
                        first=$OPTARG
                        ;;
                l)
                        last=$OPTARG
                        ;;
                e)
                        email=$OPTARG
                        ;;
                n)
                        number=$OPTARG
                        ;;
          esac
        done

        if [[ -z $first || -z $last || -z $email || -z $number ]]; then
            echo "Error!!! Some input is missing!!!" >&2
            usage # display usage
            exit 1
        fi
        echo -e "$first\t$last\t$email\t$number" >> contacts
fi