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.