И оператор в операторе case

Внутри ~/.config/dmenu-recentесть два текстовых файла с именами backgroundи terminal. Отредактируйте соответствующий в текстовом редакторе и удалите строку с названием вашего приложения. Это приведет к сбросу настроек приложения dmenu.

3
30.10.2019, 18:37
3 ответа

Вы правы в том, что стандартное определение caseне допускает использования оператора И в шаблоне. Вы также правы в том, что попытка сказать «начинается с гласной нижнего -И начинается с гласной верхнего -» ничего не даст. Также обратите внимание, что ваши шаблоны и объяснения перевернуты для начала/окончания с цифрой. Тесты --с использованием шаблона [0-9]*будут соответствовать словам, которые начинаются с цифры,не заканчивается цифрой.

Одним из подходов может быть объединение ваших тестов в один и тот же шаблон, сначала наиболее -ограничительные:

case $word in
  ([AaEeIiOoUu]??[0-9]) echo it is four characters long and begins with a vowel and ends with a digit;;
  ([AaEeIiOoUu]*[0-9])  echo it is not four characters long begins with a vowel and ends with a digit;;
#...
esac

Еще один (длинный! )подход заключается в том, чтобы вложить ваши caseутверждения, каждый раз создавая соответствующие ответы. Начинается ли оно с гласной, да или нет? Теперь, это заканчивается цифрой, да или нет? Это быстро станет громоздким и раздражающим в обслуживании.

Другим подходом может быть использование последовательности caseоператоров, которая создает строку (или массив )применимых операторов; вы даже можете добавить *catch -все шаблоны к каждому, если вы хотите предоставить «отрицательную» обратную связь («слово не начинается с гласной» и т. д. ).

result=""
case $word in
  [AaEeIiOoUu]*)
          result="The word begins with a vowel." ;;
esac

case $word in
  [0-9]*)
          result="${result} The word begins with a digit." ;;
esac

case $word in
  *[0-9])
          result="${result} The word ends with a digit." ;;
esac

case $word in
   ????)
          result="${result} You entered four characters." ;;
esac

printf '%s\n' "$result"

Для примера:

$./go.sh
Enter a word: aieee
The word begins with a vowel.
$./go.sh
Enter a word: jeff42
 The word ends with a digit.
$./go.sh
Enter a word: aiee
The word begins with a vowel. You entered four characters.
$./go.sh
Enter a word: 9arm
 The word begins with a digit. You entered four characters.
$./go.sh
Enter a word: arm9
The word begins with a vowel. The word ends with a digit. You entered four characters.

В качестве альтернативы, bash расширил синтаксис для оператора case, чтобы разрешить выбор нескольких шаблонов, если вы заканчиваете шаблон (s )с помощью;;&:

shopt -s nocasematch
case $word in
  [aeiou]*)
          echo "The word begins with a vowel." ;;&
  [0-9]*)
          echo "The word begins with a digit." ;;&
  *[0-9])
          echo "The word ends with a digit." ;;&
   ????)
          echo "You entered four characters." ;;
esac

Обратите внимание, что я удалил шаблон *catch -all, так как он будет соответствовать чему угодно и чему угодно при переходе по шаблонам таким образом. Bash также имеет параметр оболочки с именем nocasematch, который я установил выше, который включает нечувствительное к регистру -сопоставление шаблонов. Это помогает уменьшить избыточность. --Я удалил часть | [AEIOU]*шаблона.

Для примера:

$./go.sh
Enter a word: aieee
The word begins with a vowel.
$./go.sh
Enter a word: jeff42
The word ends with a digit.
$./go.sh
Enter a word: aiee
The word begins with a vowel.
You entered four characters.
$./go.sh
Enter a word: 9arm
The word begins with a digit.
You entered four characters.
$./go.sh
Enter a word: arm9
The word begins with a vowel.
The word ends with a digit.
You entered four characters.
11
27.01.2020, 21:08

Для полноты картины, хотя caseимеет |оператор ИЛИ, в нем нет оператора И, но при использовании оболочек с расширенными операторами glob (ksh, zsh, bash )вы можете реализовать И в синтаксисе шаблона :

  • ksh93оператор @(x&y&z):

      case $string in
        ( @({12}(?)&~(i:[aeiou]*)&*[0123456789]) )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    
  • zsh(с использованием~(И -НЕ )в сочетании с^(НЕ)):x~^y~^z

      set -o extendedglob
      case $string in
        ( ?(#c12)~^(#i)[aeiou]*~^*[0-9] )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    
  • ksh88, bash, используя двойное отрицание с ИЛИ(!(!(x)|!(y)|!(z)))

      shopt -s extglob # bash only
      case $string in
        ( !(!(????????????)|!([aAeEıiIİoOuU]*)|!(*[0123456789])) )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    

В любом случае помните, что за исключением zsh, где диапазоны всегда основаны на значениях кодовой точки, диапазоны, такие как [0-9], не могут надежно использоваться вне локали POSIX/C (, поэтому [0123456789]вместо приведенного выше ).

Нечувствительные к регистру операторы сопоставления ksh93 и zsh(~(i)и(#i))учитывают локаль для сравнения с учетом регистра. Например, в турецкой локали в системе GNU (#i)[aeiou]будет соответствовать İ, но не I(, потому что iв верхнем регистре — это İтам ). Чтобы получить согласованный результат независимо от локали, вы можете вместо этого жестко закодировать все возможные значения, как в подходе ksh88/bash.

6
27.01.2020, 21:08

Обычное переносимое решение для реализации И в операторах case состоит в конкатенации логических значений:

case $A$B in
    11) echo "Both conditions are true";;
    1*) echo "Condition A is true";;
    *1) echo "Condition B is true";;
    00) echo "Both conditions are false";;
     *) echo "There is an unexpected error";;
esac

Для вашего варианта использования:

printf "Enter a word: "; read word

A=0 B=0 C=0

case $word in    ( [aeiouAEIOU]* ) A=1;; esac
case $word in    ( *[0-9]        ) B=1;; esac
case $word in    ( ????          ) C=1;; esac

case $A$B$C in
  111)     echo "Four letters that start with a vowel and end with a digit" ;;
  11*)     echo "The word begins with a vowel AND ends with a digit."       ;;
  1* )     echo "The word begins with a vowel."                             ;;
  *1?)     echo "The word ends with a digit."                               ;;
   *1)     echo "The word is four letters long"                             ;;
    *)     echo "I don't understand what you've entered,"                   ;;
esac

Использование портативного корпуса для каждой логической опции. Вы можете использовать ;;&в bash или ;|в zsh. К сожалению, у ksh нет такой опции для случая.

Альтернативой для установки логических значений (в некоторых оболочках :ksh, bash, zsh по крайней мере )является:

[[ $word ==   [aeiouAEIOU]* ]] && A=1 || A=0
[[ $word ==   *[0-9]        ]] && B=1 || B=0
[[ $word ==   ????          ]] && C=1 || c=0
2
27.01.2020, 21:08

Теги

Похожие вопросы