Dizi karşılaştırması için eşit olmayan işleci kullanma


117

PHONE_TYPEDeğişkenin üç geçerli değerden birini içerip içermediğini kontrol etmeye çalıştım .

if [ "$PHONE_TYPE" != "NORTEL" ] || [ "$PHONE_TYPE" != "NEC" ] ||
   [ "$PHONE_TYPE" != "CISCO" ]
then
    echo "Phone type must be nortel,cisco or nec"
    exit
fi

Yukarıdaki kod benim için işe yaramadı, bu yüzden bunun yerine denedim:

if [ "$PHONE_TYPE" == "NORTEL" ] || [ "$PHONE_TYPE" == "NEC" ] ||
   [ "$PHONE_TYPE" == "CISCO" ]
then
    :        # do nothing
else
    echo "Phone type must be nortel,cisco or nec"
    exit
fi

Bu tür görevler için daha temiz yollar var mı?

Yanıtlar:


162

Sanırım aradığınız:

if [ "$PHONE_TYPE" != "NORTEL" ] && [ "$PHONE_TYPE" != "NEC" ] &&
   [ "$PHONE_TYPE" != "CISCO" ]

Bu eşdeğerler için kurallara De Morgan yasaları denir ve sizin durumunuzda:

not(A || B || C) => not(A) && not(B) && not (C)

Boole işlecindeki değişikliği not edin veya ve.

Oysa sen yapmaya çalıştın:

not(A || B || C) => not(A) || not(B) || not(C)

Açıkçası işe yaramadı.


28

Çok daha kısa bir yol olacaktır:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - Satır başında bir başlangıç ​​eşleştirmek için
  • $ - Çizginin sonunu eşleştirmek için
  • =~ - Bash'in yerleşik normal ifade karşılaştırma operatörü

2
Olması gerektiğini düşünüyorumif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Milan Simek

12

İyi cevaplar ve paha biçilmez bir ders;) Sadece bir notla desteklenmek istiyorum.

Kullanmayı seçtiği test türü, koda, yapıya, çevreye vb. Bağlıdır.

Bir alternatif, bir anahtar veya casedeyimi aşağıdaki gibi kullanmak olabilir :

case "$PHONE_TYPE" in
"NORTEL"|"NEC"|"CISCO")
    echo "OK"
    ;;
*)
    echo "Phone type must be nortel,cisco or nec"
    ;;
esac

İkinci bir not olarak, büyük harfli değişken isimleri kullanırken dikkatli olmalısınız. Bu, hemen hemen her zaman büyük harf olan, sistemin getirdiği değişkenler arasındaki çarpışmayı önlemektir. Böylece $phone_typeyerine $PHONE_TYPE.

Bu güvenli olsa da, tüm büyük harfleri kullanma alışkanlığınız varsa, bir gün söyleyebilirsiniz IFS="boo"ve incinmiş bir dünyadasınız.

Aynı zamanda hangisinin ne olduğunu tespit etmeyi de kolaylaştıracak.

Bir zorunluluk değil , şiddetle düşünün.


Ayrıca muhtemelen bir işlev için iyi bir adaydır. Bu çoğunlukla kodu okumayı ve bakımını kolaylaştırır. Örneğin:

valid_phone_type()
{
    case "$1" in
    "NORTEL"|"NEC")
        return 0;;
    *)
        echo "Model $1 is not supported"
        return 1;;
    esac
}

if ! valid_phone_type "$phone_type"; then
    echo "Bye."
    exit 1
fi

9

VEYA kullanmalısınız, OR değil.

if [ "$PHONE_TYPE" != "NORTEL" ] && [ "$PHONE_TYPE" != "NEC" ] && [ "$PHONE_TYPE" != "CISCO" ]
then

veya

if [ "$PHONE_TYPE" != "NORTEL" -a "$PHONE_TYPE" != "NEC" -a "$PHONE_TYPE" != "CISCO" ]
then

1

Yukarıdaki bir cevabı düzeltmek için (henüz yorum yapamadığım gibi):

PHONE_TYPE="NORTEL"
if [[ $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO|SPACE TEL)$ ]]; then 
  echo "Phone type accepted."
else
  echo "Error! Phone type must be NORTEL, CISCO or NEC."
fi

Lütfen = ~ bu kullanım için en az bash 4'e ihtiyacınız olduğunu unutmayın
. Bash 3'te çalışmaz.

MS 4.3'te bash 4.3.46 (iyi çalışıyor) ve bash 3.1.17 (işe yaramadı) kullanarak MS Windows 7'de test ettim.

= 'Nin LHS değeri tırnak içinde olmalıdır. Yukarıda, PHONE_TYPE = "SPACE TEL" de aynı olacaktır.


0

[[Yerine] kullanın

if [[ "$PHONE_TYPE" != "NORTEL" ]] || [[ "$PHONE_TYPE" != "NEC" ]] || 
   [[ "$PHONE_TYPE" != "CISCO" ]]
then
echo "Phone type must be nortel,cisco or nec"
exit 1
fi

2
Bu elbette yanlıştır. [[vs [, mantığın kapalı olmasına yardımcı olmaz.
ilkkachu

0

Sadece @ 0x80 çözümüne dayanan bir değişiklik teklifi:

# define phone brand list
phoneBrandList=" NORTEL NEC CISCO" ## separator is space with an extra space in first place

# test if user given phone is contained in the list
if [[ ${phoneBrandList} =~ (^|[[:space:]])"${userPhoneBrand}"($|[[:space:]]) ]]; then
    echo "found it !"
fi
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.