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?

munish
sumber

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.

Nils Werner
sumber
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
0x80
sumber
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
Runium
sumber
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
Jlliagre
sumber
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.

Akan
sumber
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
Swapnil
sumber
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
tdaget
sumber