Я помню, как где-то видел bash
скрипт, использующий case
и shift
для просмотра списка позиционных параметров, разбора флагов и опций с аргументами, когда он их встречает, и удаления их после анализа, чтобы оставить только пустые аргументы, которые позже обрабатываются остальной частью скрипт.
Например, при синтаксическом анализе командной строки cp -R file1 -t /mybackup file2 -f
он сначала будет проходить по параметрам, распознавать, что пользователь запросил переход в каталоги -R
, указал цель -t /mybackup
и принудительно выполнять копирование -f
, и удалить их из списка параметров, оставив программа для обработки file1 file2
в качестве оставшихся аргументов.
Но я, кажется, не могу вспомнить / выяснить, какой сценарий я когда-либо видел. Я просто хотел бы иметь возможность сделать это. Я гуглял по разным сайтам и добавлял список соответствующих страниц, которые я изучал.
Вопрос на этом веб-сайте специально задавался о «опционах, не зависящих от порядка», но как в единственном ответе, так и в ответе на вопрос, на который он был поставлен, не рассматриваются случаи, подобные описанным выше, когда варианты смешиваются с обычными аргументами, которые, как я полагаю, были причина для человека, чтобы конкретно упомянуть , независимые от порядка варианты.
Поскольку bash
встроенная getopts
функция, по - видимому, останавливается на первом аргументе, не являющемся опцией, она кажется недостаточной в качестве решения. Вот почему на странице Wooledge BashFAQ (см. Ниже) объясняется, как изменить порядок аргументов. Но я бы хотел избежать создания нескольких массивов, если список аргументов довольно длинный.
Так shift
как не поддерживает выталкивание отдельных аргументов из середины списка параметров, я не уверен, какой простой способ реализовать то, что я спрашиваю.
Я хотел бы услышать, есть ли у кого-нибудь решения для удаления аргументов из середины списка параметров без создания нового массива.
Страницы, которые я уже видел:
- http://mywiki.wooledge.org/ComplexOptionParsing#Rearranging_arguments
- http://mywiki.wooledge.org/BashFAQ/035
- Использование getopts в сценарии оболочки bash для получения длинных и коротких параметров командной строки
- http://wiki.bash-hackers.org/scripting/posparams
- http://wiki.bash-hackers.org/howto/getopts_tutorial
- аргумент bash для аргументов в $ @
- Каков канонический способ реализации независимых от порядка опций в скриптах bash?
- Как мне работать с переключателями в сценарии оболочки?
Ответы:
POSIXly, синтаксический анализ параметров должен останавливаться на
--
или на первом аргументе без опции (или аргументе без опции), в зависимости от того, что наступит раньше. Так вчто по адресу
file1
, такcp
рекурсивно должны скопировать всеfile1
,-t
,/mybackup
иfile2
в-f
каталог.getopt(3)
Однако GNU (который GNUcp
использует для разбора опций (и здесь вы используете GNU,cp
поскольку вы используете-t
опцию, специфичную для GNU )), если не установлена$POSIXLY_CORRECT
переменная окружения, принимает опции после аргументов. Так что это фактически эквивалентно синтаксическому анализу стиля опции POSIX:getopts
Оболочка встроенная, даже в GNU оболочке (bash
) обрабатывает только стиль POSIX. Он также не поддерживает длинные опции или опции с необязательными аргументами.Если вы хотите проанализировать параметры так же, как это
cp
делает GNU , вам нужно использовать GNUgetopt(3)
API. Для этого, если в Linux вы можете использовать расширеннуюgetopt
утилиту изutil-linux
( эта расширенная версияgetopt
команды также была перенесена в некоторые другие Unices, такие как FreeBSD ).Это
getopt
переставит параметры каноническим способом, что позволит вам просто проанализировать его с помощьюwhile/case
цикла.Вы обычно используете его как:
Также обратите внимание, что это
getopt
будет анализировать параметры так же, как GNUcp
. В частности, он поддерживает длинные параметры (и ввод их сокращенно) и учитывает$POSIXLY_CORRECT
переменные среды (которые при установке отключают поддержку параметров после аргументов) так же, как GNUcp
.Обратите внимание, что использование gdb и печать
getopt_long()
получаемых аргументов может помочь в создании параметров дляgetopt(1)
:Тогда вы можете использовать
getopt
как:Помните, что
cp
список поддерживаемых опций GNU может меняться от одной версии к другой, иgetopt
вы не сможете проверить, передаете ли вы, например, допустимое значение для--sparse
опции.источник
while [ "$#" -gt 0 ]
io justwhile (($#))
? Это просто чтобы избежать башизма?(($#))
это скорее кшизм .Таким образом, каждый раз, когда
getopts
обрабатывается аргумент, он не ожидает, что он устанавливает переменную оболочки$OPTIND
на следующее число в списке аргументов, которое он должен обработать и возвращает значение, отличное от 0. Если$OPTIND
задано значение 1,getopts
указывается POSIX для принятия новый список аргументов. Таким образом, он просто наблюдает заgetopts
возвратом, сохраняет приращения счетчика плюс$OPTIND
для любого неудачного возврата, смещает ошибочные аргументы и сбрасывает$OPTIND
каждую неудачную попытку. Вы можете использовать его какopts "$@"
- хотя вы хотите настроитьcase
цикл или сохранить его в переменную и изменить этот раздел наeval $case
.Во время работы он устанавливает
$args
каждый аргумент, которыйgetopts
не обрабатывается ... так что ...ВЫВОД
Это работает
bash
,dash
,zsh
,ksh93
,mksh
... ну, я перестал пытаться в этой точке. В каждой оболочке также есть$[Rtf]flag
и$targ
. Дело в том, что все числа аргументов, которыеgetopts
не хотели обрабатывать, остались.Изменение стиля параметров также не имело значения. Это работало как
-Rf -t/mybackup
или-R -f -t /mybackup
. Он работал в середине списка, в конце списка или в начале списка ...Тем не менее, самый лучший способ - просто добавить
--
конец списка параметров в список аргументов, а затем выполнить егоshift "$(($OPTIND-1))"
в концеgetopts
обработки. Таким образом вы удаляете все обработанные параметры и сохраняете конец списка аргументов.Одна вещь, которую мне нравится делать, - переводить длинные варианты в короткие - и я делаю это очень похожим образом, поэтому этот ответ пришел легко - до того, как я бегу
getopts
.источник
cp -t --file foo
илиcp -- --file foo
) и не справится с опциями, введенными сокращенно (--fi
...), или с--target=/dest
синтаксисом.getopts
вещь намного более простой функцией.opts()
имеет какое-то отношение к вашему собственному ответу, так какopts()
работает в одном цикле - касаясь каждого аргумента, но один раз - и делает это надежно (насколько я могу судить) , переносимым и без единой подоболочки.-R
,-t /mybackup
,-f
). Сейчас я оставлю свой отрицательный голос, поскольку он все еще запутан, вы используете$a
неинициализированный иargs= opts...
, скорее всего, оставитеargs
неустановленным (или установите его на то, что было раньше) послеopts
возвращения во многих оболочках (включая bash).bash
- я ненавижу это. На мой взгляд, если функция является текущей функцией оболочки, которую следует сохранить. Я обращаюсь к этим вещам - поскольку текущая функция, с большим количеством тестов, может быть надежно настроена для обработки всех случаев и даже для пометки аргумента предыдущим параметром, но я не согласна с тем, что она запутана . Как написано, это самый простой и самый прямой способ выполнения своей задачи, который я могу себе представить.test
В этом случаеshift
мало смысла, когда в каждом неудачномshift
случае вы должныreturn
. Это не предназначено, чтобы сделать иначе.