Bash / bourne'da "in" operatörü var mı?


17

Böyle bir şey çalışır bir "in" operatörü arıyorum:

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

Açıkçası, birkaç "veya" testi kullanmakla karşılaştırıldığında çok daha kısa bir ifade.

Yanıtlar:


31

Kullanabileceğiniz 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

Ör.

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

İle ksh, bash -O extglobveya zsh -o kshglob, ayrıca uzun bir topak deseni kullanabilirsiniz:

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

İle bash, ksh93veya zsh, ayrıca bir normal ifade karşılaştırma kullanabilirsiniz:

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

çift ​​parantez için herhangi bir neden? Tekrar teşekkürler!
mrjayviper

1
@mrjayviper çift braketler genişletilmiş bir test yapısıdır - AFAIK regex operatörü =~POSIX tek braket testi içinde geçerli değildir
steeldriver

1
@steeldriver Sadece [POSIX olmakla [[genişletilmiş görünüşe oradan kökenli oluyor Bash özelliği, Ksh (ve zsh olduğunu. caseörnek olsa en önemlisi POSIX olduğu
Sergiy Kolodyazhnyy

2
@ StéphaneChazelas 4.1-alfa en azından bash olduğundan, extglog'u açıkça ayarlamaya gerek yoktur. Bash değişikliklerinden : s. Model argümanını uyumluluk için == ve! = Operatörlerine [[komutuna) ayrıştırırken extglob'u geçici olarak açmaya zorlayın.
Isaac

@steeldriver $ 1 case "$1" indeğerinin tırnak içine alınmasına gerek yoktur , bu jetonda sözcük bölme veya yol adı genişletmesi yapılmaz.
Isaac

9

Bash'da bir "inç" testi yoktur, ancak regex testi vardır (bourne'da değil):

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

Ve genellikle bir değişken kullanılarak yazılır (alıntı ile daha az sorun):

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

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

Eski bir Bourne kabuğu için bir vaka eşleşmesi kullanmanız gerekir:

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

Bana kabul edilen cevap bu.
Nam G VU

6

caseKarşı kullanmak istediğiniz sabit bir evcil hayvan kümeniz varsa a kullanmak iyi ve iyidir. Ancak, deseni casegenişletilmiş parametreler içindeki alternatifi yorumlamadığı için çalışma zamanında desen oluşturmanız gerekirse işe yaramaz .

Bu yalnızca değişmez dizeyle eşleşir cat|dog|mouse:

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

Bununla birlikte, normal ifade eşleşmesine sahip bir değişken kullanabilirsiniz. Değişken belirtilmediği sürece, içindeki herhangi bir normal ifade operatörünün özel anlamları vardır.

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

İlişkilendirilebilir diziler de kullanabilirsiniz. Birinde bir anahtar olup olmadığını kontrol etmek in, Bash'in verdiği operatöre en yakın şeydir . Sözdizimi biraz çirkin olsa da:

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}Genişler xhalinde arr[$1]ayarlanır, aksi takdirde boşaltın. )


5

Sen olabilir bir kullanmak casebir in deyimi iftesti, ancak kod biraz tüylü görünecektir:

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

veya biraz daha kısa,

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

Bu, caseyalnızca cümle için desen eşleşmesini yapmak için bir ifcümle kullanıyor. Gereksiz bir doğru / yanlış testi sunar.

Sadece kullanmak daha iyidir 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

Bunu yapma:

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

veya bu:

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

... çünkü daha ifmakul bir caseifade yerine kodunuzda bir ifade kullanabilmek için sadece daha tehlikeli bir ürün ekliyorsunuz .


Büyük / küçük harfleri işlev çağrısına bölmek ve if ifadesi içindeki çıkış durumunu değerlendirmek daha iyi olmaz mıydı?
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy Ve desenin işleve bir argüman olmasına izin verilsin mi? Bir yapmak zorunda kalacak evalarasında casebu durumda açıklamada, ve hatta daha yatkın hatalar olacaktır.
Kusalananda

Bu durumda basit bir desen vardır, her biri işlev yapmak ve yapmak için konumsal parametre olarak geçirilebilir "$1"|"$2"|"$3". Ayrıca unix.stackexchange.com/a/234415/85039 Ama evet, biraz kıllı.
Sergiy Kolodyazhnyy

4

grep yaklaşmak.

if echo $1 | grep -qE "^(cat|dog|mouse)$"; then 
    echo "dollar 1 is either a cat or a dog or a mouse"
fi
  • -q ekrana herhangi bir çıktıdan kaçınmak için >/dev/null ).
  • -E genişletilmiş düzenli ifadeler için (cat|dog|mouse) yönler buna ihtiyaç duyar.
  • ^(cat|dog|mouse)$^kedi, köpek veya fare ( ) ile başlayan ( ) ve (cat|dog|mouse)ardından çizgi ( $) ile başlayan tüm satırlarla eşleşir
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.