Usando o operador not equal para comparação de cadeias


117

Tentei verificar se a PHONE_TYPEvariável contém um dos três valores válidos.

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 isso:

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

Existem maneiras mais limpas para esse tipo de tarefa?

Respostas:


162

Eu acho que você está procurando:

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

As regras para esses equivalentes são chamadas 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.


28

Uma maneira muito mais curta seria:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - Para coincidir com uma partida no início da linha
  • $ - Para corresponder ao final da linha
  • =~ - Operador de comparação de expressões regulares embutido do Bash

2
Eu acho que deveria serif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Milan Simek

12

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

Que tipo de teste se escolhe usar depende muito do código, estrutura, ambiente etc.

Uma alternativa poderia ser usar uma opção ou caseinstrução como em:

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

Como segunda observação, você deve ter cuidado usando nomes de variáveis ​​em maiúsculas. Isso evita a colisão entre variáveis ​​introduzidas pelo sistema, que quase sempre são todas maiúsculas. Assim, em $phone_typevez de $PHONE_TYPE.

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

Também tornará mais fácil identificar qual é o quê.

Não é preciso, mas um seria fortemente considerar.


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

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

1

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

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

Observe que você precisa pelo menos do bash 4 para esse uso de = ~
Ele 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.


0

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

2
É claro que isso está errado. [[vs [não ajuda com a lógica estar desativada.
ilkkachu 12/02

0

Apenas uma proposta de variação baseada na solução @ 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.