bash / bourne에 "in"연산자가 있습니까?


17

다음과 같이 작동하는 "in"연산자를 찾고 있습니다.

if [ "$1" in ("cat","dog","mouse") ]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi

예를 들어 여러 "또는"테스트를 사용하는 것에 비해 훨씬 짧은 문장입니다.

답변:


31

당신은 사용할 수 있습니다 case...esac

$ cat in.sh 
#!/bin/bash

case "$1" in 
  "cat"|"dog"|"mouse")
    echo "dollar 1 is either a cat or a dog or a mouse"
  ;;
  *)
    echo "none of the above"
  ;;
esac

전의.

$ ./in.sh dog
dollar 1 is either a cat or a dog or a mouse
$ ./in.sh hamster
none of the above

ksh, bash -O extglob또는 zsh -o kshglob, 당신은 또한 확장 된 글로브 패턴을 사용할 수 있습니다 :

if [[ "$1" = @(cat|dog|mouse) ]]; then
  echo "dollar 1 is either a cat or a dog or a mouse"
else
  echo "none of the above"
fi

bash, ksh93또는 zsh, 당신은 또한 정규 표현식 비교를 사용할 수 있습니다 :

if [[ "$1" =~ ^(cat|dog|mouse)$ ]]; then
  echo "dollar 1 is either a cat or a dog or a mouse"
else
  echo "none of the above"
fi

이중 괄호에 대한 이유가 있습니까? 다시 감사합니다!
mrjayviper 2016 년

1
@mrjayviper 이중 괄호는 확장 된 테스트 구조입니다-AFAIK 정규식 연산자 =~는 POSIX 단일 브래킷 테스트에서 유효하지 않습니다
스틸 드라이버

1
@steeldriver Only [는 POSIX이지만 [[bash, ksh의 확장 된 기능입니다 (겉에서 유래되었으며 zsh입니다. case예제는 가장 POSIX 임)
Sergiy Kolodyazhnyy

2
@ StéphaneChazelas 적어도 bash 4.1-alpha부터 extglog를 명시 적으로 설정할 필요가 없습니다. bash 변경 사항 : s. 호환성을 위해 패턴 인수를 == 및! = 연산자를 [[명령으로 구문 분석 할 때 extglob을 임시로 강제 실행하십시오.
Isaac

@steeldriver $ 1을 case "$1" in인용 할 필요가 없으며 해당 토큰에서 단어 분할이나 경로 이름 확장이 수행되지 않습니다.
Isaac

9

bash에는 "in"테스트가 없지만 정규 테스트 (bourne이 아님)가 있습니다.

if [[ $1 =~ ^(cat|dog|mouse)$ ]]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi

그리고 일반적으로 변수를 사용하여 작성합니다 (인용 문제가 적음).

regex='^(cat|dog|mouse)$'

if [[ $1 =~ $regex ]]; then
    echo "dollar 1 is either a cat or a dog or a mouse"
fi

이전 Bourne 쉘의 경우 대소 문자 구분을 사용해야합니다.

case $1 in
    cat|dog|mouse)   echo "dollar 1 is either a cat or a dog or a mouse";;
esac

이것은 나에게 받아 들여지는 대답입니다.
Nam G VU

6

case당신이 일치시키고 싶은 고정 된 애완 동물 세트가 있다면 a를 사용하는 것이 좋습니다. 그러나 case확장 된 매개 변수 내에서 대체를 해석하지 않으므로 런타임에 패턴을 빌드 해야하는 경우 작동 하지 않습니다.

이것은 리터럴 문자열과 만 일치합니다 cat|dog|mouse.

patt='cat|dog|mouse'
case $1 in 
        $patt) echo "$1 matches the case" ;; 
esac

그러나 정규식 일치와 함께 변수를 사용할 수 있습니다. 변수가 인용되지 않는 한, 그 안에있는 정규 표현식 연산자에는 특별한 의미가 있습니다.

patt='cat|dog|mouse'
if [[ "$1" =~ ^($patt)$ ]]; then
        echo "$1 matches the pattern"
fi

연관 배열을 사용할 수도 있습니다. 키가 존재하는지 확인하는 것은 inBash가 제공 하는 연산자 와 가장 가까운 것 입니다. 구문이 약간 추악하지만 :

declare -A arr
arr[cat]=1
arr[dog]=1
arr[mouse]=1

if [ "${arr[$1]+x}" ]; then
        echo "$1 is in the array"
fi

( 이 설정 ${arr[$1]+x}되어 x있으면 확장되고 arr[$1], 그렇지 않으면 비어 있습니다. )


5

당신은 수있는 용도 case에 문을 if테스트하지만, 코드는 비트 털이 보일 것입니다 :

if case "$1" in (cat|dog|mouse) true ;; (*) false; esac; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

조금 더 짧거나

if ! case "$1" in (cat|dog|mouse) false; esac; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

이것은 case절에 대한 패턴 일치를 수행하기 위해 if절 을 사용하고 있습니다. 불필요한 참 / 거짓 테스트를 소개합니다.

그냥 사용하는 것이 좋습니다 case:

case "$1" in
    cat|dog|mouse)
        printf '"%s" is one of cat, dog or mouse\n' "$1"
        ;;
    *)
        printf '"%s" is unknown\n' "$1"
esac

이 작업을 수행하지 마십시오 :

is_one_of () {
    eval "case $1 in ($2) return 0; esac"
    return 1
}

if is_one_of "$1" 'cat|dog|mouse'; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

아니면 이거:

is_one_of () (
    word=$1
    shift
    IFS='|'
    eval "case $word in ($*) return 0; esac"
    return 1
)

if is_one_of "$1" cat dog mouse; then
    printf '"%s" is one of cat, dog or mouse\n' "$1"
else
    printf '"%s" is unknown\n' "$1"
fi

... 단순히 if합리적인 case진술 대신 코드에서 진술 을 사용할 수 있도록 더 위험한 균열을 추가하기 때문 입니다.


case를 함수 호출로 나누고 if 문 내에서 종료 상태를 평가하는 것이 더 좋지 않습니까?
Sergiy Kolodyazhnyy 2018 년

@SergiyKolodyazhnyy 그리고 패턴이 함수에 대한 인수가되게 하시겠습니까? 이 경우 eval에는 case진술 중 하나를 수행해야하며 오류가 발생하기 쉽습니다.
Kusalananda

이 경우 간단한 패턴이 있으며 각각은 위치 매개 변수로 전달되어 기능하고 수행 할 수 "$1"|"$2"|"$3"있습니다. 또한 unix.stackexchange.com/a/234415/85039 그러나 예, 약간 털이 있습니다.
Sergiy Kolodyazhnyy 2018 년

4

grep 접근하다.

if echo $1 | grep -qE "^(cat|dog|mouse)$"; then 
    echo "dollar 1 is either a cat or a dog or a mouse"
fi
  • -q화면으로의 출력을 피하기 위해 (보다 빠른 유형 >/dev/null).
  • -E확장 정규 표현식의 경우 (cat|dog|mouse)측면이 필요합니다.
  • ^(cat|dog|mouse)$^고양이, 개 또는 마우스 ( (cat|dog|mouse))로 시작하는 모든 줄 ( )과 일치하는 줄 끝 ( $)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.