Using the not equal operator for string comparison

I guess you're looking for:

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

The rules for these equivalents are called De Morgan's laws and in your case meant:

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

Note the change in the boolean operator or and and.

Whereas you tried to do:

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

Which obviously doesn't work.


A much shorter way would be:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ – To match a starting at the beginning of line
  • $ – To match end of the line
  • =~ - Bash's built-in regular expression comparison operator

Good answers, and an invaluable lesson ;) Only want to supplement with a note.

What type of test one choose to use is highly dependent on code, structure, surroundings etc.

An alternative could be to use a switch or case statement as in:

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

As a second note you should be careful by using upper-case variable names. This is to prevent collision between variables introduced by the system, which almost always is all upper case. Thus $phone_type instead of $PHONE_TYPE.

Though that one is safe, if you have as habit using all upper case, one day you might say IFS="boo" and you're in a world of hurt.

It will also make it easier to spot which is what.

Not a have to but a would strongly consider.


It is also presumably a good candidate for a function. This mostly makes the code easier to read and maintain. E.g.:

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