desenv-web-rp.com

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

Eu tentei verificar se o PHONE_TYPE variá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?

134
munish

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.

193
Nils Werner

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
  • =~ - O operador de comparação de expressões regulares do Bash
38
0x80

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 switch ou case 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. Portanto $phone_type ao invés de $PHONE_TYPE.

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

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

Não é um tem que, 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
13
Runium

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
11
jlliagre

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 = ~
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.

2
Will

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
0
tdaget

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
0
Swapnil