2016-05-23 2 views
1

У меня возникли проблемы с тем, как заставить getopts принимать несколько флагов с одним аргументом. Например.Bash getopts несколько флагов с одним обязательным параметром

Флаги: Дети: а - Адам б - Beth гр - Cathy г - Дункан

Обязательный параметр: вкус мороженого

(не то, что мой сценарий на самом деле делает, но проще всего сформулировать таким образом)

Что я могу сделать прямо сейчас:

./flavor -a chocolate 

./flavor -c chocolate 

То, что я хотел бы сделать:

./flavor -acd chocolate 

Вместо того, единственное, что я могу заставить его сделать до сих пор:

./flavor -a chocolate -c chocolate -d chocolate 

Каждый вариацию я попытался с getopts либо не видит параметр вообще или требует его после каждого флага декларация. Я чувствую, что мне не хватает чего-то очевидного, что даст мне момент «ага», но я не вижу его сам. Может кто-то указать мне верное направление?

============================================

while getopts ":a:b:c:d:" opt; do 
    case $opt in 
     a) 
      do stuff with $OPTARG 
     ;; 
     b) 
      do stuff with $OPTARG 
     ;; 
     c) 
      do stuff with $OPTARG 
     ;; 
     d) 
      do stuff with $OPTARG 
     ;; 
     :) 
     echo "Option -$OPTARG requires an argument." >&2 
     exit 1 
     ;; 
    esac 
done 

================================

Приносим извинения, если это действительно глупый вопрос и спасибо за ваше время.

+0

Вам ничего не хватает; не существует способа указать, что один аргумент должен быть разделен всеми параметрами в группе. – chepner

+0

Я считаю, что вы не можете этого сделать, но я могу ошибаться. С './flavor -acd' ** a ** будет потреблять ** cd ** в качестве' $ OPTARG'. – sjsam

ответ

1

Параметры стека, требующие аргументов, не поддерживаются getopts. Вы можете использовать только те параметры, которые не принимают аргументы.

Чтобы сделать то, что вы предлагаете, требуется гораздо больше усложнений в обработке аргументов. По существу вам придется предварительно обработать параметры, чтобы узнать, где начинаются аргументы без опций. Это не особенно красива и не рекомендуется, но это делает буквально то, что вы просили, не требуя дополнительного параметра:

_GETOPTS=":abcd" 
while getopts "${_GETOPTS}" opt 
do 
    case $opt in 
     abcd) 
     : 
     ;; 
     \?) 
     echo "Unsupported option (-${OPTARG})" >&2 
     exit 1 
     ;; 
    esac 
done 
eval "FIRSTARG=\${${OPTIND}}" 
if [ -z "${FIRSTARG}" ] 
then 
    echo "Flavor argument required." 
    exit 1 
fi 
OPTIND=1 
while getopts "${_GETOPTS}" opt 
do 
    case $opt in 
     a) 
     echo do a stuff with ${FIRSTARG} 
     ;; 
     b) 
     echo do b stuff with ${FIRSTARG} 
     ;; 
     c) 
     echo do c stuff with ${FIRSTARG} 
     ;; 
     d) 
     echo do d stuff with ${FIRSTARG} 
     ;; 
    esac 
done 

Результаты:

$ ./flavor -acd chocolate 
do a stuff with chocolate 
do c stuff with chocolate 
do d stuff with chocolate 

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

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

+0

Спасибо. Это дает мне около 90% пути. Мне просто нужно выяснить, как сделать требуемый параметр сейчас, чтобы его нельзя было оставить без внимания. – Mathaen

+0

Вставить непосредственно перед вторым while, если речь идет о строках 'if [-z" $ {FIRSTARG} "]; то требуется аргумент «Вставить аромат»; выход 1; fi' – kbulgrien

+0

Yep. Работает как шарм! Еще раз спасибо. :) – Mathaen

0

Немного tweaky способ сделать это будет:

#!/bin/bash 
while getopts ":abcdf:" opt; do 
case $opt in 
f) 
FLAVOUR="$OPTARG" 

if [ ${ADAM_IN:-0} -eq 1 ] 
then 
    echo "Adam gets $FLAVOUR" 
    ADAM_IN=0 
fi 
if [ ${BETH_IN:-0} -eq 1 ] 
then 
    echo "Beth gets $FLAVOUR" 
    BETH_IN=0 
fi 
if [ ${CATHY_IN:-0} -eq 1 ] 
then 
    echo "Cathy gets $FLAVOUR" 
    CATHY_IN=0 
fi 
if [ ${DUNCAN_IN:-0} -eq 1 ] 
then 
    echo "Duncan gets $FLAVOUR" 
    DUNCAN_IN=0 
fi 
;; 
a) 
    ADAM_IN=1 
;; 
b) 
    BETH_IN=1 
;; 
c) 
    CATHY_IN=1 
;; 
d) 
    DUNCAN_IN=1 
;; 
:) 
echo "invalid argument" 2>/dev/null 
exit 1 
;; 
esac 
done 

Сохранить сценарий, как ice_cream_allocator и запустить его люблю:

$ ./ice_cream_allocator -abcf"Chocolate" -df"Vanila" -cf"Strawberry" 

Выход

Adam gets Chocolate 
Beth gets Chocolate 
Cathy gets Chocolate 
Duncan gets Vanila 
Cathy gets Strawberry 

Ну я есть мягкий угол для Кэти, поэтому давая ей два флакона ours;)

+0

Я вижу, что вы здесь делаете, но когда я упрощаю то, что делает мой сценарий (т. Е. Не мороженое), это будет невозможно. Я благодарю вас за то, что вы нашли время ответить и предложить помощь. – Mathaen

+0

@ Mathaen: Добро пожаловать, и удачи в том, что вы хотите сделать. :-) – sjsam

Смежные вопросы