Как я могу определить, что с getopts не было передано ни одной опции?


19

У меня есть этот код -

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
done
print 'hi'$name

Когда я запускаю bash getoptDemos.sh(без опции) он печатает hiвместо вызова функции usage. Он вызывает использование, когда заданы параметры, отличные от w, h и l. Тогда это не может работать, когда не указаны параметры.

Я попытался с помощью ?, \?, :вместо , *но я не могу добиться того, чего я хотел. Я имею в виду все docsна getoptговорит , что это использовать ?.

Что я делаю неправильно?


Под какой оболочкой вы его запускаете?
Джулиан

Я бегу под этим/bin/bash
Хуссейн Тамболи

Другие варианты: wiki.bash-hackers.org/howto/getopts_tutorial
ОДС

Ответы:


15

Когда вы запускаете этот скрипт без каких-либо опций, getopt возвращает false, поэтому он вообще не входит в цикл. Это просто выпадет на печать - это ksh / zsh?

Если у вас должна быть опция, лучше всего проверить $ name после цикла.

if [ -z "$name" ]
then
   usage
   exit
fi

Но $nameперед вызовом убедитесь, что он пуст getopts(так как $nameв окружении, полученном при запуске, могла быть оболочка) с

unset name

(до getoptsцикла)


нет. его удар Итак, как мне добиться того, чего я хочу - обработать no argumentусловие с помощью bash.
Хуссейн Тамболи

Если вам нужна обязательная опция, я не думаю, что это возможно - возможно, именно поэтому они называются опциями :) Вы можете проверить $ name после цикла, чтобы убедиться, что он установлен. if [-z "$ name"]; затем использование; выход ; фантастика
Джулиан

Благодарю. приведенный выше код действительно помог. Жаль getopts, что такого положения нет. Что хуже, чем это, не может отказать вам.
Хуссейн Тамболи

что если я запускаю другую оболочку? зш, ш любая оболочка кроме bash заботится об этом условии?
Хуссейн Тамболи

20

getoptsобрабатывает варианты по очереди. Это его работа. Если пользователь не передает никакой опции, первый вызов getoptsзавершает цикл while.

Если ни один из параметров не принимает аргумент, значение OPTINDуказывает, сколько параметров было передано. В общем, OPTINDэто число аргументов, которые являются опциями или аргументами опций, в отличие от не опциональных аргументов (операндов).

while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"

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


1
Благодарю. +1 для вас. когда я помещаю последние 3 строки из вашего кода в sample.sh и запускаю, bash sample.sh -abc file.txtэто дает - 1 non-option arguments. как узнать сколько вариантов было дано. (здесь 3)
Хуссейн Тамболи

1
Странно, что никто не прокомментировал эту небольшую ошибку - если никакие опции не заданы, OPTIND будет равен 1 после цикла «while getopts ...». Таким образом, проверка if должна проверять равенство с 1, а не с нулем.
Даниэль

4

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

if [[ ! $@ =~ ^\-.+ ]]
then
  #display_help;
fi

Блок проверяет, что строка параметра не начинается с -символа, что указывает на то, что первый параметр не является аргументом опции.


2

Я бы проверил это с помощью переменной. Если getopts никогда не проходит цикл в случае отсутствия аргумента, вы можете использовать это, например, так:

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}

no_args="true"
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
    no_args="false"
done

[[ "$no_args" == "true" ]] && { usage; exit 1; }

print 'hi'$name

0

Непосредственно перед вашим getoptsблоком проверьте, $1равен ли (первый аргумент / параметр, который вы передали в командной строке) пустой строке. Если это так, распечатайте сообщение об использовании и выйдите (или выполните некоторую функцию «без параметров», если вы анархист), в противном случае разрешите getoptsанализировать параметры как обычно.

Причина, по которой эта функция не включена в getopts, заключается в том, что вы уже можете выполнить ее в bash с помощью if-else. Пример:

if [[ $1 == "" ]]; then
    Your_Usage_Function;
    exit;
else
   #parse options with getopts code block here;
fi

Есть смысл?

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.