Menggunakan operator yang tidak sama untuk perbandingan string


117

Saya mencoba memeriksa apakah PHONE_TYPEvariabel berisi satu dari tiga nilai yang valid.

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

Kode di atas tidak berfungsi untuk saya, jadi saya mencoba ini sebagai gantinya:

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

Apakah ada cara yang lebih bersih untuk jenis tugas ini?

Jawaban:


162

Saya kira Anda sedang mencari:

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

Aturan untuk setara ini disebut hukum De Morgan dan dalam kasus Anda dimaksudkan:

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

Perhatikan perubahan pada operator boolean atau dan dan.

Sedangkan yang Anda coba lakukan:

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

Yang jelas tidak berhasil.


28

Cara yang jauh lebih pendek adalah:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - Untuk mencocokkan awal di awal baris
  • $ - Untuk mencocokkan ujung garis
  • =~ - Operator perbandingan ekspresi reguler bawaan Bash

2
Saya pikir itu seharusnyaif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Milan Simek

12

Jawaban yang bagus, dan pelajaran yang sangat berharga;) Hanya ingin melengkapi dengan catatan.

Jenis tes apa yang dipilih untuk digunakan sangat tergantung pada kode, struktur, lingkungan, dll.

Alternatifnya bisa menggunakan saklar atau casepernyataan seperti pada:

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

Sebagai catatan kedua Anda harus berhati-hati dengan menggunakan nama variabel huruf besar. Ini untuk mencegah tabrakan antar variabel yang diperkenalkan oleh sistem, yang hampir selalu merupakan huruf besar semua. Jadi, $phone_typebukannya $PHONE_TYPE.

Meskipun itu aman, jika Anda memiliki kebiasaan menggunakan semua huruf besar, suatu hari Anda mungkin mengatakan IFS="boo"dan Anda berada di dunia yang terluka.

Ini juga akan membuatnya lebih mudah untuk menemukan yang mana.

Tidak harus tetapi sangat akan mempertimbangkan.


Mungkin juga merupakan kandidat yang baik untuk suatu fungsi. Ini sebagian besar membuat kode lebih mudah dibaca dan dipelihara. Misalnya:

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

Anda harus menggunakan AND, bukan OR.

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

atau

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

1

Untuk memperbaiki jawaban di atas (karena saya belum dapat berkomentar):

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

Harap perhatikan bahwa Anda membutuhkan setidaknya bash 4 untuk penggunaan = ~
Ini tidak berfungsi di bash 3.

Saya menguji pada MS Windows 7 menggunakan bash 4.3.46 (berfungsi dengan baik) dan bash 3.1.17 (tidak berfungsi)

LHS dari = ~ harus dalam tanda kutip. Di atas, PHONE_TYPE = "SPACE TEL" akan cocok juga.


0

Gunakan [[sebagai gantinya

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

2
Ini tentu saja salah. [[vs [tidak membantu dengan logika dimatikan.
ilkkachu

0

Hanya proposal variasi berdasarkan pada solusi @ 0x80:

# 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.