为什么在使用getopt时选项和可选参数之间不能有空格?

9

使用 getopt 解析命令行参数时,对于必需参数,您可以在选项标志和参数之间加入空格,但对于可选参数则不行。只有当可选参数紧跟在选项后面时,才会解析可选参数。

TEMP=`getopt -o p:q:: -n 'mkqueue.sh' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

# Now go through all the options
while true ; do
    case "$1" in
        -p) echo "Option p, argument \`$2'" ; shift 2 ;;
        -q) 
            case "$2" in
                "") echo "Option q, no argument"; shift 2 ;;
                *)  echo "Option q, argument \`$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done

基于此:http://software.frodo.looijaard.name/getopt/docs/getopt-parse.bash

当我不带可选参数运行脚本时,它可以正常工作:

./mkqueue.sh -p adfsa -q
Option p, argument `adfsa'
Option q, no argument

如果我尝试在-q后面加上可选参数并在它们之间加上空格,那么它将无法工作:
./mkqueue.sh -p adfsa -q sdfasdfa
Option p, argument `adfsa'
Option q, no argument

如果选项和参数之间没有空格,它就可以工作,即使必需参数需要空格。
./mkqueue.sh -p adfsa -qsdfasdfa
Option p, argument `adfsa'
Option q, argument `sdfasdfa'

这个问题有解决方法吗?


2
如果允许的话,你会遇到另一个问题。假设你的程序还接受一个位置参数。./a.out -q foo bar应该解析为./a.out -qfoo bar还是./a.out -q -- foo bar - 5gon12eder
1
@5gon12eder,如果你把那个作为答案,你至少会得到我的点赞。它解释了“为什么”,这正是这个问题的标题所问的。 :) - Charles Duffy
1个回答

11

getopt 的 man 页面中记录了这种限制:

一个简单的短选项是以 `-' 开头,然后是一个短选项字符。如果该选项有必须参数,则可以直接在选项字符之后写入,或作为下一个参数(即在命令行上由空格分隔)。如果选项有可选参数,则必须在选项字符后面直接写入。

虽然 getopt 允许“可选选项参数”,但一般认为这是个坏主意。例如,Posix 实用程序语法指南 包括:

指南7:选项参数不应该是可选的。

这个指南的基本原因是根据惯例,命令行选项的参数可以是任何字符串。例如,它可能看起来像另一个选项。它可能是字面字符串 --,通常表示选项列表的结尾。它可能是一个空字符串。任何东西。

“可选选项参数”的问题在于,唯一确定可选选项参数是否提供的方法是将其后续的参数识别为选项或--。但这意味着可选参数值不能以 - 开头。

或者,您可以选择由命令行实用程序 getopt 采取的解决方案,即要求可选参数紧接在选项后面,没有间隔空格(即在同一个单词中)。但是在这种情况下,可选参数不能是空字符串。

与其为解决这些歧义创建复杂的规则,简单的解决方案是——Posix(以及我这个权威性较小的人)推荐不将选项参数作为可选项。如果一个命令行选项有一个常见值,而你又想通过不要求用户输入来简化用户的生活,那么可以实现两个不同的命令行选项,一个带一个参数,另一个不带。通常的技术包括使用一个小写字符表示不带参数的版本,相应的大写字符表示带参数的版本,或者对该版本使用长选项(--option)。
对于那些喜欢紧凑且详细解释的人来说,Posix 的 解释 解释道:
“指南7允许任何字符串都成为选项参数;选项参数可以以任何字符开头,可以是---,也可以是空字符串。例如,命令pr -h -pr -h --pr -h -dpr -h +2pr -h''包含选项参数----d+2和一个空字符串。相反,命令pr -h -- -d-d视为选项而不是参数,因为这里的--是选项参数,而不是定界符。”

这是一个很好的解释,而且很完整,但我认为有点密集。详细解释一下理论的例子可能会更有帮助(例如,并不是每个人都知道--代表什么)。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接