¿Cómo se representan múltiples condiciones en una instrucción shell if?

Quiero representar varias condiciones como esta:

if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ] then echo abc; else echo efg; fi 

pero cuando ejecuto el script, muestra

 syntax error at line 15: `[' unexpected, 

donde la línea 15 es la que muestra si ….

¿Qué está mal con esta condición? Supongo que algo está mal con el () .

Técnica clásica (metacaracteres de escape):

 if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ] then echo abc else echo efg fi 

Adjunto las referencias a $g entre comillas dobles; esa es una buena práctica, en general. Estrictamente, los paréntesis no son necesarios porque la precedencia de -a y -o hace correcto incluso sin ellos.

Tenga en cuenta que los operadores -a y -o son parte de la especificación POSIX para test , también conocido como [ , principalmente por compatibilidad con versiones anteriores (ya que fueron parte de la test en la 7ma edición UNIX, por ejemplo), pero están explícitamente marcados como ‘obsoletos’ ‘por POSIX. Bash (ver expresiones condicionales ) parece adelantarse a los significados clásicos y POSIX para -a y -o con sus propios operadores alternativos que toman argumentos.


Con cierto cuidado, puede usar el operador más moderno [[ , pero tenga en cuenta que las versiones en Bash y Korn Shell (por ejemplo) no necesitan ser idénticas.

 for g in 1 2 3 do for c in 123 456 789 do if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]] then echo "g = $g; c = $c; true" else echo "g = $g; c = $c; false" fi done done 

Ejemplo ejecutado, usando Bash 3.2.57 en Mac OS X:

 g = 1; c = 123; true g = 1; c = 456; false g = 1; c = 789; false g = 2; c = 123; false g = 2; c = 456; true g = 2; c = 789; false g = 3; c = 123; false g = 3; c = 456; false g = 3; c = 789; false 

No necesita citar las variables en [[ como lo hace con [ porque no es un comando separado de la misma manera que [ es.


¿No es una pregunta clásica?

Yo lo hubiera pensado así. Sin embargo, hay otra alternativa, a saber:

 if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ] then echo abc else echo efg fi 

De hecho, si lee las pautas de ‘shell portátil’ para la herramienta autoconf o paquetes relacionados, esta notación – usando ‘ || ‘y’ && ‘- es lo que recomiendan. Supongo que podrías llegar tan lejos como:

 if [ "$g" -eq 1 ] && [ "$c" = "123" ] then echo abc elif [ "$g" -eq 2 ] && [ "$c" = "456" ] then echo abc else echo efg fi 

Donde las acciones son tan triviales como un eco, esto no está mal. Cuando el bloque de acción que se repetirá es de líneas múltiples, la repetición es demasiado dolorosa y es preferible una de las versiones anteriores, o debe envolver las acciones en una función que se invoca en los diferentes bloques.

En Bash:

 if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]] 

Usando /bin/bash lo siguiente funcionará:

 if [ "$option" = "Y" ] || [ "$option" = "y" ]; then echo "Entered $option" fi 
 $ g=3 $ c=133 $ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg" efg $ g=1 $ c=123 $ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg" abc 

Tenga cuidado si tiene espacios en sus variables de cadena y comprueba la existencia. Asegúrate de citarlos apropiadamente.

 if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then 
 #!/bin/bash current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print $5'} ) echo $current_usage critical_usage=6% warning_usage=3% if [[ ${current_usage%?} -lt ${warning_usage%?} ]]; then echo OK current usage is $current_usage elif [[ ${current_usage%?} -ge ${warning_usage%?} ]] && [[ ${current_usage%?} -lt ${critical_usage%?} ]]; then echo Warning $current_usage else echo Critical $current_usage fi