desarrollo-web-br-bd.com

Usar el operador no igual para la comparación de cadenas

Traté de verificar si el PHONE_TYPE variable contiene uno de los tres 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

El código anterior no funcionó para mí, así que intenté esto en su lugar:

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

¿Hay formas más limpias para este tipo de tarea?

134
munish

Supongo que estás buscando:

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

Las reglas para estos equivalentes se llaman leyes de De Morgan y en su caso significan:

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

Tenga en cuenta el cambio en el operador booleano o y y.

Mientras que trataste de hacer:

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

Lo que obviamente no funciona.

193
Nils Werner

Una forma mucho más corta sería:

if [[ ! $PHONE_TYPE =~ ^(NORTEL|NEC|Cisco)$ ]]; then 
  echo "Phone type must be nortel, Cisco or nec."
fi
  • ^ - Para coincidir con un comienzo al principio de la línea
  • $ - Para coincidir con el final de la línea
  • =~ - Operador de comparación de expresiones regulares incorporado de Bash
38
0x80

Buenas respuestas y una lección invaluable;) Solo quiero complementar con una nota.

El tipo de prueba que uno elija usar depende en gran medida del código, la estructura, el entorno, etc.

Una alternativa podría ser usar un modificador o una instrucción case como en:

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

Como segunda nota, debe tener cuidado al usar nombres de variables en mayúsculas. Esto es para evitar la colisión entre variables introducidas por el sistema, que casi siempre es todo en mayúsculas. Así $phone_type en lugar de $PHONE_TYPE.

Aunque ese es seguro, si tiene la costumbre de usar mayúsculas, algún día podría decir IFS="boo" y estás en un mundo de dolor.

También hará que sea más fácil detectar qué es qué.

No es un tiene que pero sería muy importante considerarlo.


También es presumiblemente un buen candidato para una función. Esto hace que el código sea más fácil de leer y mantener. P.ej.:

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

Debe usar AND, no 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
11
jlliagre

Para corregir una respuesta anterior (como todavía no puedo 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

Tenga en cuenta que necesita al menos bash 4 para este uso de = ~
No funciona en bash 3.

Probé en MS Windows 7 usando bash 4.3.46 (funciona bien) y bash 3.1.17 (no funcionó)

El LHS de = ~ debe estar entre comillas. Arriba, PHONE_TYPE = "SPACE TEL" también coincidiría.

2
Will

Solo una propuesta de variación basada en la solución @ 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 [[en su lugar

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