Sử dụng toán tử không bằng nhau để so sánh chuỗi


117

Tôi đã cố kiểm tra xem PHONE_TYPEbiến có chứa một trong ba giá trị hợp lệ không.

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

Đoạn mã trên không hoạt động với tôi, vì vậy tôi đã thử cách này:

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

Có những cách sạch hơn cho loại nhiệm vụ này?

Câu trả lời:


162

Tôi đoán bạn đang tìm kiếm:

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

Các quy tắc cho những tương đương này được gọi là luật của De Morgan và trong trường hợp của bạn có nghĩa là:

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

Lưu ý sự thay đổi trong toán tử boolean hoặc và.

Trong khi bạn đã cố gắng làm:

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

Mà rõ ràng là không hoạt động.


28

Một cách ngắn hơn nhiều sẽ là:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - Để phù hợp với một bắt đầu ở đầu dòng
  • $ - Để phù hợp với cuối dòng
  • =~ - Toán tử so sánh biểu thức chính quy tích hợp của Bash

2
Tôi nghĩ rằng nên như vậyif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Milan Simek

12

Câu trả lời hay, và một bài học vô giá;) Chỉ muốn bổ sung bằng một ghi chú.

Loại thử nghiệm nào bạn chọn sử dụng phụ thuộc nhiều vào mã, cấu trúc, môi trường xung quanh, v.v.

Một cách khác có thể là sử dụng một công tắc hoặc casecâu lệnh như trong:

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

Là một lưu ý thứ hai, bạn nên cẩn thận bằng cách sử dụng tên biến chữ hoa. Điều này là để ngăn xung đột giữa các biến được giới thiệu bởi hệ thống, mà hầu như luôn luôn là chữ hoa. Như vậy $phone_typethay vì $PHONE_TYPE.

Mặc dù điều đó là an toàn, nhưng nếu bạn có thói quen sử dụng tất cả chữ hoa, một ngày nào đó bạn có thể nói IFS="boo"và bạn đang ở trong một thế giới bị tổn thương.

Nó cũng sẽ làm cho nó dễ dàng hơn để phát hiện đó là những gì.

Không phải là một phải nhưng một mạnh mẽ sẽ xem xét.


Nó cũng có lẽ là một ứng cử viên tốt cho một chức năng. Điều này chủ yếu làm cho mã dễ đọc và bảo trì hơn. Ví dụ:

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

Bạn nên sử dụng AND, không phải OR.

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

hoặc là

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

1

Để sửa câu trả lời ở trên (như tôi chưa thể nhận xét):

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

Xin lưu ý rằng bạn cần ít nhất bash 4 cho việc sử dụng này = ~
Nó không hoạt động trong bash 3.

Tôi đã thử nghiệm trên MS Windows 7 bằng bash 4.3.46 (hoạt động tốt) và bash 3.1.17 (không hoạt động)

LHS của = ~ nên được trích dẫn. Ở trên, PHONE_TYPE = "SPACE TEL" cũng khớp.


0

Sử dụng [[thay vào đó

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

2
Điều này, tất nhiên, sai. [[vs [không giúp đỡ với logic bị tắt.
ilkkachu

0

Chỉ là một đề xuất biến thể dựa trên giải pháp @ 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.