Bash 为什么我不能使用getopt在选项和可选参数之间留一个空格?

Bash 为什么我不能使用getopt在选项和可选参数之间留一个空格?,bash,getopt,Bash,Getopt,当使用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! eva

当使用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
(基于此:)

当我在没有可选参数的情况下运行脚本时,它会工作:

./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'

是否对此进行了修复?

该限制记录在
getopt
的手册页中:

简单的短选项是一个“-”,后跟一个短选项字符。如果该选项有一个必需的参数,那么它可以直接写在选项字符之后,或者作为下一个参数(即,在命令行上用空格分隔)如果选项有可选参数,则必须直接写在选项字符(如果有)之后。

尽管
getopt
允许“可选选项参数”,但它们通常被认为是个坏主意。例如,Posix包括:

准则7:选项参数不应是可选的

此准则的基本原因是,按照惯例,命令行选项的参数可以是任何字符串。例如,它可能看起来像另一个选项。它可能是文本字符串
--
,通常表示选项列表的结尾。它可能是一个空字符串。什么都行

“可选选项参数”的问题在于,知道未提供可选选项参数的唯一方法是将以下参数识别为选项或
--
。但这意味着可选参数的值不能以
-
开头

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

与其创建复杂的规则来解决这些歧义,简单的解决方案——由Posix推荐(由我推荐,权限要小得多)——是不允许选项参数是可选的。如果命令行选项有一个公共值,并且您希望通过不要求键入来简化用户的生活,那么实现两个不同的命令行选项,其中一个接受参数,另一个不接受参数。常用的技术包括对没有参数的版本使用小写字符,对有参数的版本使用相应的大写字符,或者对该版本使用长选项(
--option

对于那些喜欢密集和紧凑解释的人,Posix解释说:

准则7允许任何字符串作为选项参数;选项参数可以以任何字符开头,可以是
-
-
,也可以是空字符串。例如,命令
pr-h-
pr-h-
pr-h-d
pr-h+2
,和
pr-h'
分别包含选项参数
-
-
-d
+2
,以及一个空字符串。相反,命令
pr-h--d
将-d视为选项,而不是参数,因为
--
在这里是选项参数,而不是分隔符


如果允许的话,你会遇到另一个问题。假设您的程序也接受位置参数。应该将
/a.out-q foo bar
解析为
/a.out-qfoo bar
还是
/a.out-q--foo bar
?@5gon12eder,如果你有这个答案,你至少会得到我的支持票。它解释了这个问题的标题所问的“为什么”。)这是一个很好的解释,而且完整,但我觉得有点晦涩。将基本原理的示例稍微解包一下可能会有所帮助(不是每个人都知道
--
的意思,f'rinstance)。