Case ... esa c условие по умолчанию - PullRequest
0 голосов
/ 08 апреля 2020

Я использую getopts и case...esac в первый раз. Я видел учебные пособия и вопросы с различными шаблонами для опции по умолчанию / catch-all: ?, *, \?, [?]. Кажется, что все они функционируют одинаково, как вы можете видеть, если вы измените их порядок в этом сценарии:

#!/bin/bash
set -e
set -u
set -o pipefail

while getopts ":d:l:h:" opt; do
    case $opt in
        d)  echo getopts saw $opt with value $OPTARG ;;
        l)  echo getopts saw $opt with value $OPTARG ;;
        h)  echo getopts saw $opt with value $OPTARG ;;
        :)  echo "getopts saw $opt with value $OPTARG and went to :" ;;
        *)  echo "getopts saw $opt with value $OPTARG and went to *" ;;
        ?)  echo "getopts saw $opt with value $OPTARG and went to ?" ;;
        \?) echo "getopts saw $opt with value $OPTARG and went to \?" ;;
        [?]) echo "getopts saw $opt with value $OPTARG and went to [?]" ;;
    esac
done
echo script done

Выполнение приведенного ниже кода всегда остановится на первом соответствующем параметре в списке case:

$ ./test.sh -c
getopts saw ? with value c and went to *
script done

Все ли они одинаковы?

В ответ на комментарий @ BenjaminW. В приведенной ниже цитате из руководства поясняется, что getopts вернет ? против : в зависимости от того, установлен ли getopts в беззвучный режим. Итак, мои модифицированные вопросы:

  • Являются ли ?, \? и [?] эквивалентными?
  • Является ли * ненужным?

Из руководства: Если требуемый аргумент не найден и getopts не молчит, ставится вопросительный знак ('?') в имени OPTARG не установлен, и выводится сообщение о диагностике c. Если getopts молчит, в имени ставится двоеточие (':'), а для OPTARG устанавливается найденный символ опции.

Ответы [ 4 ]

5 голосов
/ 08 апреля 2020

Только * является значением по умолчанию для case.

Причина, по которой другие работают в этом сценарии, заключается в том, что вы обрабатываете getopts результаты. Он устанавливает $opt в ? для любой опции, которая не указана в аргументе getopts, и вы уже обрабатываете все эти опции явно.

Но если бы вы обрабатывали более общие данные, вы бы не не может использовать ? в качестве регистра по умолчанию.

4 голосов
/ 08 апреля 2020

Все ли они одинаковы?

Нет. Они одинаковы:

        \?)  echo "getopts saw $opt with value $OPTARG and went to ?" ;;
        [?]) echo "getopts saw $opt with value $OPTARG and went to \?" ;;

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

        ?)  echo "getopts saw $opt with value $OPTARG and went to ?" ;;

..., который соответствует строкам, состоящим ровно из одного символа, любого символа. И это опять отличается от ...

        *)  echo "getopts saw $opt with value $OPTARG and went to *" ;;

..., который соответствует любой строке любой длины, включая ноль.

Однако все эти альтернативы имеют тот же эффект в вашем конкретном коде, потому что, если getopt видит символ опции, которого нет в строке опции, то он устанавливает назначенную переменную в один знак вопроса. Все вышеупомянутые шаблоны соответствуют этому, и у вас есть другие, более ранние случаи для всех букв параметров в строке параметров, которые вы используете.

Единственный истинный универсальный шаблон для оператора case - * .

1 голос
/ 08 апреля 2020

Они означают разные вещи (кроме двух одинаковых):

  • \? соответствует только вопросительному знаку: ?
  • [?] также соответствует только знак вопроса.
  • ? соответствует любому отдельному символу, например a, :, P и ?
  • * соответствует любому числу любого символа, как a, apple, ?, :centipede== и пустая строка.

Когда getopts обрабатывает опцию, которую он не распознает, он устанавливает opt в буквальный знак вопроса ?. Вы заметите, что, хотя шаблоны соответствуют разным вещам, они все делят ? как возможное соответствие. Поэтому все они выполняют свою работу в указанном вами c случае.

Однако лучший способ - использовать \? или [?], чтобы соответствовать случаю неподдерживаемой опции, и дополнительно использовать * чтобы поймать любые опции / значения, которые вы не учли:

#!/bin/bash
set -e
set -u
set -o pipefail

while getopts ":d:l:h:x" opt; do
    case $opt in
        d)  echo getopts saw $opt with value $OPTARG ;;
        l)  echo getopts saw $opt with value $OPTARG ;;
        h)  echo getopts saw $opt with value $OPTARG ;;
        :)  echo "getopts saw $opt with value $OPTARG and went to :" ;;
        \?) echo "getopts option not recognized" ;;
        *)  echo >&2 "Oops, unhandled $opt! Please file a bug!"
            exit 1
           ;;
    esac
done
echo script done

Таким образом, флаги, которые вы утверждаете для обработки, но не такие, как -x, добавленные здесь, или ошибки кода, которые sh переменная opt будет правильно помечена как ошибка в скрипте и не будет сообщена как ошибка пользователя.

0 голосов
/ 08 апреля 2020

поставить регистр с * в конец, потому что этот параметр соответствует одному или нескольким символам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...