2

我写了一个使用 getopt 命令的 shell 脚本。提供给 getopt 命令的长选项列表包括以下三个不同的选项:

localaddress
localport
listen

当我运行我的脚本时

myscript.sh --local xxxx

它显然包含一个模棱两可的选项(--local),getopt 将其返回为“--local-address”和一个零代码。

++ getopt -o a:p: --long localaddress:,localport: -- --local 172.30.2.4
+ AUX='-- --localaddress '\''172.30.2.4'\'

但如果我尝试

myscript.sh --l xxxx

这里 getopt 确实发现它模棱两可:

getopt: option `--l' is ambiguous

鉴于 getopt(1) 的手册页显示,我认为这种行为很奇怪:

Long options may be abbreviated, as long as the abbreviation is not ambiguous.

我错过了什么?

提前感谢

PD:在 RHEL5 中测试

附录

在阅读了Jonathan Leffler的答案后,我尝试了一些测试——注意冒号模式:

# getopt -V
getopt (enhanced) 1.1.4    
# getopt -o a:p: --long localaddress,localport,listen -- --l xxx 
 --localaddress -- 'xxx'
# getopt -o a:p: --long localaddress,localport,listen: -- --l xxx 
getopt: option `--l' is ambiguous
 -- 'xxx'
# getopt -o a:p: --long localaddress,localport:,listen -- --l xxx 
getopt: option `--l' is ambiguous
 -- 'xxx'
# getopt -o a:p: --long localaddress,localport:,listen: -- --l xxx 
getopt: option `--l' is ambiguous
 -- 'xxx'
# getopt -o a:p: --long localaddress:,localport,listen -- --l xxx 
getopt: option `--l' is ambiguous
 -- 'xxx'
# getopt -o a:p: --long localaddress:,localport,listen: -- --l xxx 
getopt: option `--l' is ambiguous
 -- 'xxx'
# getopt -o a:p: --long localaddress:,localport:,listen -- --l xxx 
getopt: option `--l' is ambiguous
 -- 'xxx'
# getopt -o a:p: --long localaddress:,localport:,listen: -- --l xxx 
 --localaddress 'xxx' --

2014-05-26 更新——测试 getopt_long(3)

我创建了一个简单的 C 程序来测试 getopt_long(3) 函数。

在我的源代码中,传递给 getopt_long(3) 的结构“option”的数组包含三个长选项“xxaaa”、“xxxyy”和“xxxzz”的定义——它们都以相同的字符串“xx”开头测试 getopt_long(3) 检测模糊选项的能力。

/*
            FIELD NAMES OF option STRUCTURE
      name            has_arg      flag   val
*/
   { "xxaaa",       no_argument,   NULL,   9},
   { "xxxyy",       no_argument,   NULL,   7},
   { "xxxyz",       no_argument,   NULL,   7},
   { "mmmAA",       no_argument,   NULL,   3},
   { "mmmBB", required_argument,   NULL,   3},

(有关这些字段用途的详细信息,请参阅 getopt_long(3) 的手册页)。

请注意,“--xx”这样的模棱两可的选项有三个可能的候选者,但“---xxx”只有两个候选者。

getopt_long 的行为根据名为“has_arg”和“val”的两个结构字段的值而变化:

WHEN
  the value of "val" field is the same in every possible candidate
    AND
  the value of the "has_arg" field is the same in every possible candidate,
THEN
  the function getopt_long wrongly complains NOTHING about ambiguity
  and the first candidate is returned
OTHERWISE
  an error message about ambiguity is reported.

从上面的例子:

test 1. "--xxx" is WRONGLY admitted as "--xxxyy".
test 2. "--xx" is properly refused as ambiguous.
test 3. "--mmm" is properly refused as ambiguous.

getopt(1) 命令在每个“用户定义的长选项”的“val”字段中分配一个 2(在源代码中标记为 LONG_OPT)。在启动此线程的情况下,“选项”结构的数组将如下所示:

   { "localaddress",    required_argument,   NULL,   2},
   { "localport",       required_argument,   NULL,   2},

因此,getopt(1) 检测不明确的长选项的唯一方法是候选者在其“has_arg”字段中具有不同的值。

问题

Q1. Why does getopt_long(3) behave that way?
Q2. Why does getopt_long_only(3) not?
Q3. How can the creators of getopt_long(3) be notified? -- I'm not into the linux kernel
    development nor I do not use to visit linux kernel websites.

解决方法建议

由于我还不能回答 Q1,我认为可能会修改 getopt(1) 命令的源代码,以在“val”字段中为每个用户定义的长选项分配不同的值,而不是相同的 2 (LONG_OPT) 值。由于 getopt_long(3) 可以在短选项的情况下返回单个 ASCII 字符,因此这些值应该不属于 ASCII 映射 -- val >= 256

4

1 回答 1

0

非常好奇!我至少名义上运行的是相同版本的getopt(诚然不在 RHEL5 上,它已经相当老了,现在,IIRC - 不是那个年龄与它有太大关系),但我无法重现你得到的结果。对于附录中的每个操作示例,我都会收到警告消息getopt: option `--l' is ambiguous(退出状态getopt为 1,表示失败)。

测试脚本

for la in '' :
do
    for lp in '' :
    do
        for li in '' :
        do
            (
            set -x
            getopt -o a:p: --long localaddress${la},localport${lp},listen${li} -- --l xxx
            )
            echo $?
        done
    done
done

示例输出

+ getopt -o a:p: --long localaddress,localport,listen -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress,localport,listen: -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress,localport:,listen -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress,localport:,listen: -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress:,localport,listen -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress:,localport,listen: -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress:,localport:,listen -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1
+ getopt -o a:p: --long localaddress:,localport:,listen: -- --l xxx
getopt: option `--l' is ambiguous
 -- 'xxx'
1

这是自洽的,并且与文档一致。您可以运行显示的脚本并验证输出吗?

于 2014-05-17T16:07:10.590 回答