Объясните команду оболочки: shift $ (($ optind - 1))

30

Я не парень по Linux, но застрял в каком-то скрипте, который я должен прочитать для своего проекта. Так кто-нибудь может мне помочь, что делает эта команда?

shift $(($optind - 1))
Гаурав Пант
источник
3
Как отмечено ниже, OPTIND должен быть в верхнем регистре, а '$' внутри круглых скобок является необязательным.
DarkHeart

Ответы:

49

shift $((OPTIND-1))(примечание OPTINDв верхнем регистре) обычно находится сразу после getopts whileцикла. $OPTINDэто количество вариантов найденных getopts.

Как упоминает pauljohn32 в комментариях, строго говоря, OPTINDдает позицию следующего аргумента командной строки.

Из Справочного руководства по GNU Bash :

имя опционной строки getopts [args]

getoptsиспользуется сценариями оболочки для анализа позиционных параметров. optstringсодержит опционные символы, которые должны быть распознаны; если за символом следует двоеточие, ожидается, что параметр имеет аргумент, который должен отделяться от него пробелом. Двоеточие (':') и вопросительный знак ('?') Нельзя использовать в качестве дополнительных символов. Каждый раз, когда он вызывается, getoptsпомещает следующую опцию в имя переменной оболочки, инициализируя, nameесли она не существует, и индекс следующего аргумента, который будет обработан, в переменную OPTIND. OPTINDустанавливается в 1 каждый раз, когда вызывается оболочка или сценарий оболочки. Когда для опции требуется аргумент, getopts помещает этот аргумент в переменную OPTARG. Оболочка не сбрасываетсяOPTIND автоматически; он должен быть сброшен вручную между несколькими вызовами в getoptsпределах одного вызова оболочки, если должен использоваться новый набор параметров.

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

getoptsобычно анализирует позиционные параметры, но если дано больше аргументов args, getoptsвместо этого анализирует их.

shift n
удаляет n строк из списка позиционных параметров. Таким образом shift $((OPTIND-1))удаляет все параметры, которые были проанализированы getoptsиз списка параметров, и поэтому после этой точки $1будет ссылаться на первый не опциональный аргумент, переданный сценарию.

Обновить

Как упоминает mikeserv в комментарии, shift $((OPTIND-1))может быть небезопасно. Чтобы предотвратить нежелательное расщепление слов и т. Д., Все расширения параметров должны быть заключены в двойные кавычки. Таким образом, безопасная форма для команды

shift "$((OPTIND-1))"

PM 2Ring
источник
Кажется, что это будет работать правильно, только если все опции встречаются до любых оставшихся позиционных аргументов. Правильный?
Стив Йоргенсен
@ SteveJorgensen: Да, это правильно. OTOH, размещение опций после неопционных аргументов противоречит соглашению sh / bash. Как правило, первые аргументы, которые не начинаются с дефиса, означают конец опций, а любые последующие аргументы, начинающиеся с дефиса, не считаются опциями. Не все программы придерживаются этого соглашения, но оно делает жизнь намного проще, если вы это делаете. :)
PM 2Ring
@SteveJorgensen: (продолжение) Эта тема кратко обсуждается в разделе Почему некоторые утилиты анализируют операнды перед опциями? , Как упоминает комментарий Жиля к ответу Селады, некоторые программы (например find) могут выглядеть так, как будто они разрешают опции после неопций, но они этого не делают: у них есть операнды, начинающиеся с тире.
PM 2Ring
Спасибо за эту информацию (и редактирование) @mosvy Это довольно необычно IFS, но лучше быть в безопасности, чем потом сожалеть. ;)
PM 2Ring
@roaima if IFS=0123456789, shift $((OPTIND-1))(без кавычек) превратится в, shift ""который будет игнорироваться (in ksh) или генерировать ошибку (in bashи dash).
мосвы
8

$((...))просто рассчитывает вещи. В вашем случае он принимает значение $optintи вычитает 1.

shiftудаляет позиционные параметры. В вашем случае это удаляет optint-1параметры.

Для получения дополнительной информации посмотрите на help getopts, help shift, взгляд на man bashдля «Арифметика расширения», и особенно Google для getopts.

Михась
источник