Case 문의 AND 연산자

Case 문의 AND 연산자

다음 코드가 있습니다.

read -p "Enter a word: " word

case $word in
  [aeiou]* | [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." ;;
  [aeiou]* && [AEIOU]* && *[0-9])
          echo "The word begins with vowel and ends with a digit." ;;
   ????)
          echo "You entered a four letter word." ;;
   *)
          echo "I don't know what you've entered," ;;
esac

내가 이것을 실행할 때 :

Enter a word: apple123
case2.sh: line 10: syntax error near unexpected token `&&'
case2.sh: line 10: `  [aeiou]* && [AEIOU]* && *[0-9])'

Case 문은 AND 연산자를 지원하지 않는 것으로 보이며, 위 Case 문에서 && 연산자는 논리적으로 올바르지 않다고 생각합니다.

if else를 사용하여 입력이 모음과 숫자로 시작하는지 확인할 수 있다는 것을 알고 있습니다. 하지만 케이스에 AND 연산자와 같은 내장 함수가 있는지 궁금합니다.

답변1

당신 말이 맞아요표준 정의case패턴에는 AND 연산자가 허용되지 않습니다. "소문자 모음으로 시작하고 대문자 모음으로 시작합니다"라고 말하면 아무 것도 일치하지 않는다는 것도 맞습니다. 또한 패턴과 설명이 숫자 테스트의 시작/끝을 반대로 한다는 점에 유의하세요. [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명령문을 사용하여 적용 가능한 명령문의 문자열(또는 배열)을 구축하는 것 입니다("단어 true;*아니요모음으로 시작합니다' 등).

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.

또는,casebash는 문의 구문을 확장합니다.다음으로 패턴을 끝내면 여러 패턴을 선택할 수 있습니다 ;;&.

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

*이 방법으로 패턴을 탐색하면 무엇이든 일치하므로 포괄적인 패턴을 제거했습니다 . 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.

답변2

완전성을 위해 OR 연산자 case는 있지만 |AND 연산자는 없지만 확장된 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~((NOT )과 결합하여 (AND-NOT)을 사용하세요 ^.)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, , bashOR( )을 사용한 !(!(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]일치 항목이 있지만 대문자가 있기 때문에 일치 İ하지 않습니다 . (로케일에 관계없이) 일관된 결과를 얻으려면 ksh88/bash 접근 방식 대신 가능한 모든 값을 하드코딩하는 것이 좋습니다.Iiİ

답변3

대개가지고 다닐 수 있는Case 문에서 AND를 구현하는 솔루션은 부울 값을 연결하는 것입니다.

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

관련 정보