Usando o operador não igual para comparação de cadeia

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

O código acima não funcionou para mim, então tentei:

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

Existem maneiras mais limpas para esse tipo de tarefa?

    
por munish 14.03.2013 / 10:50

6 respostas

113

Acho que você está procurando:

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

As regras para esses equivalentes são chamadas de leis de De Morgan e, no seu caso, significam:

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

Observe a alteração no operador booleano ou e e.

Considerando que você tentou fazer:

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

O que obviamente não funciona.

    
por 14.03.2013 / 10:57
16

Um caminho muito mais curto seria:

if [[ $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
    
por 14.03.2013 / 16:26
9

Você deve usar ANDs, não ORs.

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

ou

if [ "$PHONE_TYPE" != "NORTEL" -a "$PHONE_TYPE" != "NEC" -a "$PHONE_TYPE" != "CISCO" ]
then
    
por 14.03.2013 / 10:57
5

Boas respostas e uma lição inestimável;) Só quero complementar com uma nota.

O tipo de teste que escolhemos usar é altamente dependente de código, estrutura, ambiente etc.

Uma alternativa poderia ser usar um switch ou uma declaração case como em:

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

Como segunda nota, você deve ter cuidado ao usar nomes de variáveis maiúsculas. Isso é para evitar a colisão entre as variáveis introduzidas pelo sistema, que quase sempre é tudo em maiúsculas. Assim $phone_type em vez de $PHONE_TYPE .

Embora este seja seguro, se você tem o hábito de usar todas as letras maiúsculas, um dia você pode dizer IFS="boo" e você está em um mundo de mágoa.

Também será mais fácil identificar qual é o motivo disso.

Não é necessário , mas seria strongmente considerado.

Também é presumivelmente um bom candidato para uma função. Isso torna o código mais fácil de ler e manter. Por exemplo:

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
    
por 14.03.2013 / 12:25
2

Use [[em vez

if [[ "$PHONE_TYPE" != "NORTEL" ]] || [[ "$PHONE_TYPE" != "NEC" ]] || 
   [[ "$PHONE_TYPE" != "CISCO" ]]
then
echo "Phone type must be nortel,cisco or nec"
exit 1
fi
    
por 08.07.2015 / 21:20
0

Para corrigir uma resposta acima (como não posso comentar ainda):

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

Por favor, note que você precisa pelo menos bash 4 para este uso de = ~
Não funciona no bash 3.

Eu testei no MS Windows 7 usando o bash 4.3.46 (funciona bem) e o bash 3.1.17 (não funcionou)

O LHS do = ~ deve estar entre aspas. Acima, PHONE_TYPE="SPACE TEL" também corresponderia.

    
por 13.04.2018 / 16:49