it-swarm.com.ru

Как использовать шаблоны в выражении case в скриптах bash?

На странице man говорится, что операторы case используют «сопоставление с шаблоном расширения имени файла».
Я обычно хочу иметь короткие имена для некоторых параметров, поэтому я иду:

case $1 in
    req|reqs|requirements) TASK="Functional Requirements";;
    met|meet|meetings) TASK="Meetings with the client";;
esac

logTimeSpentIn "$TASK"

Я пробовал шаблоны типа req* или me{e,}t, которые, как я понимаю, будут правильно расширяться, чтобы соответствовать этим значениям в контексте расширения имени файла, но это не работает.

57
Ramiro Rela

Расширение скобок не работает, но *, ? и [] делают. Если вы установите shopt -s extglob, то вы также можете использовать расширенное сопоставление с образцом :

  • ?() - ноль или одно вхождение паттерна
  • *() - ноль или более вхождений шаблона
  • +() - одно или несколько вхождений паттерна
  • @() - одно вхождение шаблона
  • !() - все, кроме шаблона

Вот пример:

shopt -s extglob
for arg in Apple be cd meet o mississippi
do
    # call functions based on arguments
    case "$arg" in
        a*             ) foo;;    # matches anything starting with "a"
        b?             ) bar;;    # matches any two-character string starting with "b"
        c[de]          ) baz;;    # matches "cd" or "ce"
        me?(e)t        ) qux;;    # matches "met" or "meet"
        @(a|e|i|o|u)   ) fuzz;;   # matches one vowel
        m+(iss)?(ippi) ) fizz;;   # matches "miss" or "mississippi" or others
        *              ) bazinga;; # catchall, matches anything not matched above
    esac
done
115
Dennis Williamson

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

Согласно руководству Bash о случае в Условные конструкции .

Каждый pattern подвергается тильде расширение, расширение параметра, подстановка команд и арифметика расширение.

Ничего о Расширение Брейс к сожалению.

Так что вам нужно сделать что-то вроде этого:

case $1 in
    req*)
        ...
        ;;
    met*|meet*)
        ...
        ;;
    *)
        # You should have a default one too.
esac
35
plundra

if и grep -E более портативное решение

Для переносимости я рекомендую использовать только операторы if и grep -E, который поддерживает расширенные регулярные выражения , например:

arg='abc'
if echo "$arg" | grep -Eq 'a.c|d.*'; then
  echo 'first'
Elif echo "$arg" | grep -Eq 'a{2,3}'; then
  echo 'second'
fi

POSIX 7

По-видимому, Bash следует POSIX по умолчанию без shopt, как указано в https://stackoverflow.com/a/4555979/895245

Вот цитата: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_01 раздел «Конструктивное условное построение»:

Случай условной конструкции должен выполнить составной список, соответствующий первому из нескольких шаблонов (см. Нотацию соответствия шаблонов) [...] Несколько шаблонов с одним составным списком должны быть разделены знаком «|» условное обозначение. [...]

Формат для конструкции case выглядит следующим образом:

case Word in
     [(] pattern1 ) compound-list ;;
     [[(] pattern[ | pattern] ... ) compound-list ;;] ...
     [[(] pattern[ | pattern] ... ) compound-list]
  esac

а затем http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 раздел «2.13. Обозначение соответствия шаблону» упоминает только ?, * и [].