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