getopt не находит двусмысленных необязательных аргументов

Я написал сценарий оболочки, который использует команду getopt. Список длинных параметров, предоставляемых команде 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

Дополнение

После того, как я прочитал ответ Джонатана Леффлера, я попробовал несколько тестов — обратите внимание на шаблон двоеточия:

# 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' --

ОБНОВЛЕНИЕ от 26 мая 2014 г. -- тестирование getopt_long(3)

Я создал простую программу на C для тестирования функции getopt_long(3).

В моем исходном коде массив структуры «option», переданный в getopt_long(3), содержит определение трех длинных опций «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) присваивает значение 2 (помеченное как LONG_OPT в исходном коде) в поле «val» каждой «определенной пользователем длинной опции». В случае запуска этого потока массив структур «option» будет выглядеть так:

   { "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.

РЕШЕНИЕ ПРЕДЛОЖЕНИЕ

Поскольку я пока не могу ответить на вопрос 1, я думаю, что исходный код команды getopt(1) может быть изменен для присвоения разных значений в поле «val» для каждой определяемой пользователем длинной опции вместо одного и того же значения 2 (LONG_OPT). Так как getopt_long(3) может возвращать один символ ASCII в случае коротких опций, эти значения должны выпадать из карты ASCII -- val >= 256


person Jdamian    schedule 16.05.2014    source источник
comment
Когда я тестировал это, я запустил: /usr/gnu/bin/getopt -o a:p: --long localaddress:,localport: -- --local 172.30.2.4 --loc 10.1.2.3 и получил вывод (две строки): /usr/gnu/bin/getopt: option `--local' is ambiguous и /usr/gnu/bin/getopt: option `--loc' is ambiguous. Здесь используется getopt (enhanced) 1.1.4 (из /usr/gnu/bin/getopt --version) — скомпилировано в Mac OS X (работает на 10.9.3, но построено на более ранней версии).   -  person Jonathan Leffler    schedule 16.05.2014


Ответы (1)


Очень любопытный! Я, по крайней мере, номинально использую ту же версию 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

Это непротиворечиво и согласуется с документацией. Можете ли вы запустить показанный скрипт и проверить вывод?

person Jonathan Leffler    schedule 17.05.2014
comment
Результаты таковы: первый и последний тест сообщают 0 (недвусмысленно), остальные сообщают 1 (неоднозначно). Протестировано в RHEL 4 (getopt 1.1.3), RHEL 5 (getopt 1.1.4) и RHEL 6.4 (getopt 1.1.4). - person Jdamian; 19.05.2014
comment
Очень любопытный. У меня нет объяснения тому, что вы видите. Вы ведь не возились с $IFS? - person Jonathan Leffler; 19.05.2014
comment
Нет, Джонатан, не видел. - person Jdamian; 19.05.2014
comment
Предложение: получите исходный код getopt 1.1.5, скомпилируйте его и посмотрите, получите ли вы различные результаты, используя это. Предполагается, что это будет выпуск с исправлением сборки, а не выпуск с исправлением ошибок, поэтому теоретически это не должно иметь никакого значения. Или получите версию 1.1.4 по тому же URL-адресу. Вам может понадобиться использовать ./getopt в каталоге сборки, чтобы вызвать его. - person Jonathan Leffler; 19.05.2014
comment
Эй, Джонатан. Такое же поведение обнаружено на SMP-машине с сервером 2.6.28-19 # 66-Ubuntu - первый и последний тест сообщают 0 (недвусмысленно), другие сообщают 1 (неоднозначно). - person Jdamian; 19.05.2014
comment
В ПОРЯДКЕ; Я могу воспроизвести это на Ubuntu 14.04, но там версия getopt from util-linux 2.20.1. Очень любопытный. Мне это кажется ошибкой. Может стоит сообщить об этом мейнтейнерам? И тогда возникает вопрос: «Какие сопровождающие?» (Отмечу, что текущая версия util-linux — 2.24. , хотя он вышел всего несколько недель (2014-04-24), поэтому неудивительно, что его еще нет в дистрибутивах Версия 2.23 была выпущена 2013-07-31, поэтому у нее было больше времени, чтобы ее подобрать. - person Jonathan Leffler; 19.05.2014
comment
Я скачал util-linux 2.13 и скомпилировал getopt (1.1.4). Такое же поведение обнаружено. Я предполагаю, что функция getopt_long(3) ошибочна, потому что она возвращает код LONG_OPT (что означает, что я нашел длинную опцию), когда предоставляется неоднозначная опция - она ​​должна возвращать '?' - person Jdamian; 20.05.2014
comment
Я скачал util-linux 2.13 и скомпилировал getopt. Такое же поведение обнаружено. - person Jdamian; 20.05.2014
comment
Когда используется опция getopt -a (вынуждающая использовать вызов getopt_long_only(3)), getopt правильно сообщает, что опция неоднозначна. - person Jdamian; 20.05.2014