linux GNU getopt: игнорировать неизвестные необязательные аргументы?

Можно ли игнорировать неизвестные необязательные аргументы с помощью GNU getopt?

У меня есть сценарий scriptA.sh с необязательными аргументами --optA, --optB, --optC, --optD.

Я хотел бы написать оболочку, wrapperA, с двумя необязательными аргументами, --optX and --optY, которая вызывает scriptA. Однако я не хочу объявлять все необязательные параметры scriptA внутри оболочки.

В частности, если внутри wrapperA я указываю необязательные аргументы с помощью

getopt --longoptions optX:,optY:

звонок

wrapperA --optX --optA --optB

возвращает ошибку

getopt: unknown option -- optA

Можно ли заставить GNU getopt игнорировать неизвестные аргументы и помещать их после «-» в свой вывод?


person user3830744    schedule 11.07.2014    source источник


Ответы (4)


Невозможно указать GNU getopt игнорировать неизвестные параметры. Если вам действительно нужна эта функция, вам придется написать собственный анализатор опций.

Это не так просто, как просто игнорировать неизвестные параметры. Как узнать, принимает ли неизвестная опция аргумент или нет?

Пример использования оригинального скрипта:

originalscript --mode foo source

здесь foo является аргументом опции --mode. в то время как source является «параметром без опций» (иногда называемым «позиционным параметром»).

Пример использования скрипта-оболочки:

wrapperscript --with template --mode foo source

Откуда getopt в wrapperscript знает, что он должен игнорировать --mode вместе с foo? Если он просто игнорирует --mode, тогда originalscript получит foo в качестве первого позиционного параметра.

Возможный обходной путь — сообщить пользователям вашего скрипта-оболочки, чтобы они писали все параметры, предназначенные для исходного скрипта, после двойного дефиса (--). По соглашению двойное тире отмечает конец опций. GNU getopt распознает двойное тире и прекращает синтаксический анализ, а остальное возвращает как позиционные параметры.

Смотрите также:

person lesmana    schedule 11.07.2014
comment
Благодарю за ваш ответ. Двойной тире для завершения списка опций будет работать в моем случае. Что касается игнорирования неизвестных опций, я понимаю вашу точку зрения - это не так просто, как кажется. Моя первоначальная идея состояла в том, чтобы отодвинуть все неизвестные параметры -- в выводе getopt (--с шаблоном -- в режиме источника foo). Однако это будет работать только в том случае, если последующая обработка параметров будет передана исходному сценарию. Как вы сказали, у оболочки нет возможности узнать, принимают ли параметры исходного сценария аргументы. - person user3830744; 12.07.2014
comment
Была аналогичная проблема, двойное тире работает как шарм. - person Andrei LED; 30.11.2015

Я работал над похожей вещью и обнаружил, что это работает, чтобы ошибки getopt не мешали мне этими ошибками. В основном просто отправьте ошибки в забвение.

while getopts "i:s:" opt > /dev/null 2>&1; do
    case $opt in
      i)
        END=$OPTARG
      ;;
    esac
done
./innerscript $*

$ ./blah.sh -s 20140503 -i 3 -a -b -c

person michael salmon    schedule 16.09.2014
comment
Это прерывается, если отсутствующий аргумент принимает OPTARG. gist.github.com/cirosantilli/2a803442add75e0f1e164cde183999d3 GNU Bash 4.3.48. - person Ciro Santilli 新疆再教育营六四事件ۍ 02.11.2017
comment
Это также прерывается, если недопустимые параметры передаются перед допустимыми. - person trysis; 30.11.2017

Если вы хотите просто игнорировать stderr, добавьте 2>dev/null к начальной строке while, как показано ниже. Я думаю, вы можете использовать это и для getopt.

while getopts "a:p:" opt 2>/dev/null
do
    case $opt in
      \?)
        echo "any error comment you want" 1>&2
        exit 1
        ;;
    esac
done
person Yunhong Min    schedule 02.01.2019

Ну, я мог бы обойти проблему. Идея состоит в том, чтобы возиться с OPTIND при встрече с неизвестной опцией, чтобы синтаксический анализ мог быть продолжен getopts. Следовательно, нам нужно было бы сохранить то, где мы были при синтаксическом анализе, чтобы OPTIND можно было соответствующим образом скорректировать.

local parse_index=1 # initialize to cater for the first option coming out unknown
while getopts ':m:t:r:u:p:' opt; do
  case $opt in
    m) build_module="$OPTARG"
       parse_index=$OPTIND
       ;;
    t) build_tag="$OPTARG"
       parse_index=$OPTIND
       ;;
    r) container_registry="$OPTARG"
       parse_index=$OPTIND
       ;;
    u) registry_username="$OPTARG"
       parse_index=$OPTIND
       ;;
    p) registry_password="$OPTARG"
       parse_index=$OPTIND
       ;;
    :) echo "Option -$OPTARG requires an argument" >/dev/stderr
       ;;
   \?) echo "Unknown option: -$OPTARG"
       ((OPTIND = $parse_index + 2))    # fool `getopts` to continue parsing
       parse_index=$OPTIND      # adjust to cater for successive unknown options
       ;;
  esac
done

Я использовал предположение, что за неизвестными вариантами следует аргумент, поэтому часть ((OPTIND = $parse_index + 2)) адаптируется к вашему случаю. Предположение оказывается хрупким и не всеобъемлющим, но работает в этих обстоятельствах. Также обратите внимание, что он по-прежнему прерывается в случае ошибки (отсутствует аргумент).

Видимо, не общий и чистый подход, тем не менее, помог выйти из ситуации, когда другой альтернативы не нашлось.

person Reza Shojaee    schedule 22.04.2020