Использование оператора неравенства для сравнения строк

117

Я попытался проверить, PHONE_TYPEсодержит ли переменная одно из трех допустимых значений.

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

Приведенный выше код не работает для меня, поэтому я попробовал это вместо:

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

Есть ли более чистые способы для этого типа задач?

Munish
источник

Ответы:

162

Я думаю, вы ищете:

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

Правила для этих эквивалентов называются законами де Моргана и в вашем случае означают:

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

Обратите внимание на изменение логического оператора или и и и.

В то время как вы пытались сделать:

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

Что, очевидно, не работает.

Нильс Вернер
источник
28

Гораздо более короткий путь будет:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - чтобы соответствовать началу в начале строки
  • $ - чтобы соответствовать концу строки
  • =~ - Встроенный оператор сравнения регулярных выражений Bash
0x80
источник
2
Я думаю, что это должно бытьif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Милан Симек
12

Хорошие ответы и бесценный урок;) Хочется только дополнить запиской.

Какой тип теста выбрать, зависит от кода, структуры, окружения и т. Д.

Альтернативой может быть использование переключателя или caseоператора, как в:

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

В качестве второго замечания вы должны быть осторожны, используя имена переменных в верхнем регистре. Это необходимо для предотвращения столкновения между переменными, введенными системой, которые почти всегда имеют верхний регистр. Таким образом, $phone_typeвместо $PHONE_TYPE.

Хотя это безопасно, если у вас есть привычка использовать верхний регистр, вы можете сказать, что однажды IFS="boo"вы окажетесь в мире боли.

Это также поможет определить, что к чему.

Не обязательно, но настоятельно рекомендуется.


Это также, по-видимому, хороший кандидат на функцию. В основном это облегчает чтение и обслуживание кода. Например:

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
источник
9

Вы должны использовать AND, а не OR.

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

или же

if [ "$PHONE_TYPE" != "NORTEL" -a "$PHONE_TYPE" != "NEC" -a "$PHONE_TYPE" != "CISCO" ]
then
jlliagre
источник
1

Чтобы исправить ответ выше (я пока не могу комментировать):

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

Обратите внимание, что для этого использования вам необходим как минимум bash 4 = ~
В bash 3 это не работает.

Я тестировал на MS Windows 7, используя bash 4.3.46 (работает нормально) и bash 3.1.17 (не работал)

LHS = ~ должен быть в кавычках. Выше PHONE_TYPE = "SPACE TEL" тоже будет соответствовать.

Будет
источник
0

Используйте [[вместо

if [[ "$PHONE_TYPE" != "NORTEL" ]] || [[ "$PHONE_TYPE" != "NEC" ]] || 
   [[ "$PHONE_TYPE" != "CISCO" ]]
then
echo "Phone type must be nortel,cisco or nec"
exit 1
fi
Swapnil
источник
2
Это, конечно, неправильно. [[vs [не помогает с отключенной логикой.
Ильккачу
0

Просто предложение по варианту на основе решения @ 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
источник