Utilizzo dell'operatore non uguale per il confronto delle stringhe


117

Ho provato a verificare se la PHONE_TYPEvariabile contiene uno dei tre valori validi.

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

Il codice sopra non ha funzionato per me, quindi ho provato questo invece:

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

Ci sono modi più puliti per questo tipo di attività?

Risposte:


162

Immagino che tu stia cercando:

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

Le regole per questi equivalenti sono chiamate leggi di De Morgan e nel tuo caso significavano:

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

Notare la modifica nell'operatore booleano oe e.

Considerando che hai provato a fare:

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

Che ovviamente non funziona.


28

Un modo molto più breve sarebbe:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then 
  echo "Phone type must be nortel, cisco or nec."
fi
  • ^ - Per abbinare un inizio all'inizio della riga
  • $ - Per abbinare la fine della linea
  • =~ - Operatore di confronto delle espressioni regolari incorporato di Bash

2
Penso che dovrebbe essereif [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|CISCO)$ ]]; then
Milan Simek l'

12

Buone risposte e una lezione inestimabile;) Voglio solo integrare con una nota.

Quale tipo di test si sceglie di utilizzare dipende fortemente da codice, struttura, ambiente ecc.

Un'alternativa potrebbe essere quella di utilizzare uno switch o caseun'istruzione come in:

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

Come seconda nota, dovresti fare attenzione usando i nomi delle variabili maiuscole. Questo per evitare la collisione tra le variabili introdotte dal sistema, che quasi sempre è tutto maiuscolo. Così $phone_typeinvece di $PHONE_TYPE.

Anche se quello è sicuro, se hai l'abitudine di usare tutte le maiuscole, un giorno potresti dire IFS="boo"e sei in un mondo di dolore.

Sarà anche più facile individuare qual è la cosa.

Non è necessario ma uno prenderebbe in seria considerazione.


Presumibilmente è anche un buon candidato per una funzione. Questo per lo più semplifica la lettura e la manutenzione del codice. Per esempio:

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

Dovresti usare gli AND, non gli OR.

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

o

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

1

Per correggere una risposta sopra (come non posso ancora commentare):

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

Si noti che è necessario almeno bash 4 per questo uso di = ~
Non funziona in bash 3.

Ho provato su MS Windows 7 usando bash 4.3.46 (funziona bene) e bash 3.1.17 (non ha funzionato)

L'LHS di = ~ dovrebbe essere tra virgolette. Sopra, anche PHONE_TYPE = "SPACE TEL" corrisponderebbe.


0

Usa [[invece

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

2
Questo è, ovviamente, sbagliato. [[vs [non aiuta a disattivare la logica.
ilkkachu,

0

Solo una proposta di variazione basata sulla soluzione @ 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.