即使命令行上有 none,Getopt 也会生成双破折号 (--),并且不会验证无关参数

Getopt generates a double-dash (--) even if there's none on the command line, and doesn't validate an extraneous argument

我正在学习 getopt 命令并使用以下诊断脚本来研究其工作原理:

$ cat test-getopt.sh
#!/bin/bash
args=`getopt ab:c $*`
set -- $args
for i
do
    echo "-->$i"
done
echo $#

在以下情况下我无法理解它的行为。你能澄清一下吗?

我已经浏览了 getopt man page as well as some tutorials,但无法给出明确的解释。

根据getopt manpage

Normally, no non-option parameters output is generated until all options and their arguments have been generated. Then '--' is generated as a single parameter, and after it the non-option parameters in the order they were found, each as a separate parameter.

-- 本身是用来表示选项结束的。 (在它之后,如果有的话,生成位置参数。)

我想这样做是为了统一——无论用户是否在命令行上指定 --,都使用相同的代码逻辑。


在第二种情况下,c 是位置参数。 getopt 不会以任何方式检查位置参数,而是按原样传递。联机帮助页没有说明验证非选项参数:

getopt is used to break up (parse) options in command lines for easy parsing by shell procedures, and to check for legal options.


最后,请注意,要正确处理带空格的参数,您需要: 使用 $@ 而不是 $*;引用; evalset;并使用 getopt 的增强模式——按照 Example of how to parse options with bash/getopt。还应使用 bash -e 模式在无效选项上退出程序:

#!/bin/bash -e
args=`getopt -o ab:c -- "$@"`
eval set -- "$args"
for i
do
  echo "-->$i"
done
echo $#

$ ./test-getopt.sh -b "arg ument"
-->-b
-->arg ument
-->--
3

$ ./test-getopt.sh -d ; echo $?
getopt: unknown option -- d
1

此外,根据同一示例,使用 shiftwhile 循环可能比 for 更方便,因为它:可以轻松获取下一个参数 - 获取选项的参数并检查是否有参数(如果它是可选的);完成选项后检查剩余(位置)参数的数量。

我通常使用这样的结构来 运行 getopts:

# Set defaults
opt_a=0; opt_b=""; opt_c=false

# Step through options
while getopts ab:c opt; do
        case "$opt" in
                a) opt_a=1 ;;
                b) opt_b="${OPTARG:?The -b option requires an argument.}" ;;
                c) opt_c=true ;;
                *) usage; exit 64 ;;
        esac
done
shift $((OPTIND - 1))

在最后像这样使用 shift 会导致您的位置参数向后移动,这样 getopts 不能 处理的第一个参数变成 </code>。例如,如果上面的代码片段是名为 <code>foo 的脚本的一部分,则可能 运行:

$ foo -ab meh smoo blarg

会将 $opt_a 设置为 1,将 $opt_b 设置为 "meh",将 </code> 设置为 <code>"smoo",将 </code> 设置为<code>"blarg" 用于代码段之后的脚本部分。