web-dev-qa-db-ja.com

bash / bourneに「in」演算子はありますか?

次のように機能する「in」演算子を探しています。

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

これは、たとえば、いくつかの「または」テストを使用する場合と比較して、明らかに短いステートメントです。

18
mrjayviper

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

kshbash -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

bashksh93または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
33
steeldriver

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 Shellの場合は、大文字と小文字を一致させる必要があります。

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

caseを使用しても問題ありません。マッチするペットのセットが決まっている場合は問題ありません。ただし、ランタイムでパターンを構築する必要がある場合は機能しません。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

連想配列を使用することもできます。キーが存在するかどうかを確認することは、Bashが提供するin演算子に最も近いものです。構文は少し醜いですが:

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}は、arr[$1]が設定されている場合はxに展開され、それ以外の場合は空になります。

6
ilkkachu

あなたはcouldcaseテストで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ステートメントをコードで使用できるようにするためです。

5
Kusalananda

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)_)で始まり、その後に行末が続くすべての行に一致します(_$_)
4
steve