Condicionales en Bash: test, [ ] y [[ ]] explicados con ejemplos prácticos

DUGLAS MORENODUGLAS MORENO 👁 15

Introducción

Cuando escribís scripts de Bash, necesitás tomar decisiones basadas en el estado del sistema, el contenido de archivos o la entrada del usuario. Las estructuras condicionales son la base para controlar el flujo de ejecución: si se cumple una condición, se ejecuta un bloque de código; si no, se sigue otro camino o se termina el script. En este tutorial vas a aprender a usar los diferentes mecanismos que Bash ofrece para evaluar expresiones: el comando test, su sinónimo [ ] y la versión mejorada [[ ]]. Veremos cómo comparar números y cadenas, cómo combinar condiciones con operadores lógicos y cómo escribir bloques if‑else claros y robustos. Al final, tendrás varios scripts de ejemplo con su salida esperada, además de buenas prácticas y errores comunes que debés evitar.

1. El comando test y sus sinónimos

El comando test evalúa una expresión y devuelve un estado de salida: 0 si la condición es verdadera, 1 si es falsa. Este estado es lo que Bash usa en los if. Por conveniencia, Bash también permite escribir la misma expresión entre corchetes simples [ ] o entre doble corchete [[ ]]. Aunque [ ] es prácticamente un sinónimo de test, [[ ]] agrega funcionalidades extra y evita algunos problemas de análisis de palabras y expansión de nombres de archivo.

Sintaxis básica

test EXPRESIÓN
[ EXPRESIÓN ]
[[ EXPRESIÓN ]]

Los tres formatos son equivalentes en cuanto al resultado lógico, pero difieren en cómo tratan los operadores y los operandos. A lo largo del post vamos a usar principalmente [ ] y [[ ]] porque son más legibles en scripts.

2. Diferencias entre [ ] y [[ ]]

Característica [ ] (test) [[ ]]
Portabilidad POSIX, funciona en sh, dash, bash Bash‑only (también en ksh, zsh)
Operadores lógicos -a (AND), -o (OR) &&, `
Comparaciones de cadenas = y != (necesitan quoting) == y != (permite patrones)
Expresiones regulares No soportadas directamente =~ para regex
Manejo de palabras vacías Puede producir errores si la variable está sin definir o contiene espacios Más tolerante, pero sigue necesitando quoting en algunos casos
Expansión de nombres de archivo Sí, los corchetes simples hacen globbing No, evita expansión de patrones como * o ?

En la práctica, si escribís scripts que solo van a correr en Bash (la mayoría de los casos), usá [[ ]] por su seguridad y legibilidad. Reservá [ ] para cuando necesitás máxima portabilidad a otros shells POSIX.

3. Comparaciones de números

Para comparar enteros Bash provee un conjunto de operadores específicos. No podés usar los símbolos matemáticos habituales (<, >, ==) dentro de [ ] sin que se interpreten como redirección o asignación. En su lugar, usá los operadores de test:

  • -eq : igual a
  • -ne : diferente de
  • -lt : menor que
  • -le : menor o igual que
  • -gt : mayor que
  • -ge : mayor o igual que

Estos operadores funcionan tanto en [ ] como en [[ ]]. En [[ ]] también podés usar los símbolos <, >, <=, >= siempre que los operandos sean tratados como números (Bash los compara lexicográficamente si no se fuerza a número, así que es más seguro usar los operadores -eq etc.).

Ejemplo 1: validar edad

#!/usr/bin/env bash
edad=19

if [[ $edad -ge 18 ]]; then
    echo "Sos mayor de edad."   # salida esperada: Sos mayor de edad.
else
    echo "Sos menor de edad."   # no se ejecuta
fi

Al ejecutar este script con edad=19 veremos la primera línea. Si cambiamos edad a 15, la salida será "Sos menor de edad."

Ejemplo 2: rango de valores

#!/usr/bin/env bash
nota=82

if [[ $nota -ge 90 ]]; then
    echo "Excelente"
elif [[ $nota -ge 75 ]]; then
    echo "Bueno"
elif [[ $nota -ge 60 ]]; then
    echo "Aprobado"
else
    echo "Desaprobado"
fi

Salida esperada para nota=82: "Bueno" .

4. Comparaciones de cadenas

Para cadenas, los operadores más usados son:

  • = o == : igualdad (en [[ ]] podés usar cualquiera)
  • != : desigualdad
  • < : menor que (orden lexicográfico)
  • > : mayor que
  • -z : cadena vacía
  • -n : cadena no vacía

En [ ] tenés que usar = y !=; en [[ ]] también podés usar == y !=. Además, [[ ]] permite comparaciones con patrones usando == y != con comodines (*, ?, [...]).

Ejemplo 3: verificar si un usuario está vacío

#!/usr/bin/env bash
usuario=""

if [[ -z $usuario ]]; then
    echo "No se proporcionó nombre de usuario."   # salida esperada
else
    echo "Usuario: $usuario"
fi

Si $usuario está vacío, se imprime el mensaje de error. Si le asignamos un valor, por ejemplo usuario="ana", la salida será Usuario: ana.

Ejemplo 4: comparación lexicográfica

#!/usr/bin/env bash
palabra1="manzana"
palabra2="banana"

if [[ $palabra1 < $palabra2 ]]; then
    echo "'$palabra1' viene antes que '$palabra2' en orden alfabético."   # salida esperada
else
    echo "'$palabra1' viene después o es igual a '$palabra2'."
fi

Como "manzana" es lexicográficamente menor que "banana", se imprimirá la primera línea.

Ejemplo 5: uso de patrones con [[ ]]

#!/usr/bin/env bash
archivo="informe_final.pdf"

if [[ $archivo == *.pdf ]]; then
    echo "El archivo es un PDF."   # salida esperada
else
    echo "El archivo no es un PDF."  # no se ejecuta
fi

El patrón *.pdf coincide con cualquier cadena que termine en .pdf.

5. Operadores lógicos

Para combinar condiciones podés usar los operadores lógicos de Bash:

  • && : AND (y)
  • || : OR (o)
  • ! : NOT (negación)

Estos operadores funcionan dentro de [[ ]]. En [ ] tenés que usar -a y -o, pero su uso es menos legible y puede generar ambigüedades con la precedencia.

Ejemplo 6: rango con AND

#!/usr/bin/env bash
edad=25

if [[ $edad -ge 18 && $edad -le 30 ]]; then
    echo "Edad dentro del rango joven adulto."   # salida esperada
else
    echo "Edad fuera del rango."   # no se ejecuta
fi

Ejemplo 7: cualquiera de dos condiciones con OR

#!/usr/bin/env bash
dia="sábado"

if [[ $dia == "sábado" || $dia == "domingo" ]]; then
    echo "Es fin de semana."   # salida esperada
else
    echo "Es día hábil."   # no se ejecuta
fi

Ejemplo 8: negación

#!/usr/bin/env bash
archivo="datos.txt"

if [[ ! -f $archivo ]]; then
    echo "El archivo $archivo no existe."   # se ejecuta si el archivo falta
else
    echo "El archivo $archivo está presente."   # se ejecuta si existe
fi

Si creamos el archivo datos.txt antes de correr el script, veremos la segunda línea; si lo borramos, la primera.

6. Estructuras if‑elif‑else y case

Además de los simples if-else, Bash ofrece elif para encadenar múltiples condiciones y case para comparar un valor contra varios patrones de forma más limpia cuando hay muchas opciones.

Ejemplo 9: menú con case

#!/usr/bin/env bash
opcion="2"

case $opcion in
    1) echo "Opción uno elegida."   ;;   # no se ejecuta
    2) echo "Opción dos elegida."   ;;   # salida esperada
    3) echo "Opción tres elegida."   ;;   # no se ejecuta
    *) echo "Opción no válida."      ;;   # no se ejecuta
esac

Al cambiar opcion a 1 o 3 veremos el mensaje correspondiente; cualquier otro valor disparará el caso *.

Ejemplo 10: validación de entrada numérica con bucle

#!/usr/bin/env bash
read -p "Ingresá un número entre 1 y 10: " num

while ! [[ $num =~ ^[0-9]+$ ]] || [[ $num -lt 1 || $num -gt 10 ]]; do
    echo "Entrada inválida. Por favor, ingresá un número entre 1 y 10."   # se repite mientras la condición sea verdadera
    read -p "Ingresá un número entre 1 y 10: " num
done

echo "Gracias! El número ingresado fue $num."   # salida esperada tras ingreso válido

Este script combina expresión regular (=~) para asegurarse de que la entrada sea solo dígitos y luego verifica el rango con -lt y -gt.

7. Buenas prácticas

  1. Siempre quoteá las variables dentro de los corchetes cuando haya riesgo de que contengan espacios o estén vacías. Ejemplo: [[ "$var" == "valor" ]].
  2. Preferí [[ ]] sobre [ ] en scripts Bash por su mejor manejo de operadores lógicos y patrones.
  3. Usá los operadores de prueba adecuados para cada tipo de dato: -eq, -lt etc. para números; =, !=, -z, -n para cadenas.
  4. Evité la mezcla de estilos: no mezclés -a/-o con &&/|| dentro del mismo [ ] porque la precedencia puede confundir.
  5. Indentá claramente los bloques if, elif, else y case para mejorar la legibilidad.
  6. Comentá las condiciones complejas para que futuros lectores (o vos mismo en el futuro) comprendan rápidamente el intent.
  7. Probá los scripts con set -euo pipefail al inicio para que errores en variables no definidas o en comandos fallen temprano.
  8. Usá [[ $var == *pat* ]] para coincidencias de subcadenas en lugar de expresiones regulares cuando sea suficiente; es más rápido y legible.
  9. Cuando necesité comparaciones de punto flotante, recordá que Bash no soporta floats nativamente; recurrí a bc o awk.
  10. Documentá la salida esperada en los comentarios del script, como hemos hecho en los ejemplos, para facilitar pruebas y mantenimiento.

8. Errores comunes

  • Olvidar los espacios alrededor de los corchetes: [ $var=5 ] es interpretado como una asignación o como un comando llamado [ con un solo argumento. La forma correcta es [ "$var" -eq 5 ].
  • Usar = en vez de == dentro de [ ] para patrones: [ $var == foo* ] no funciona como se espera; el corchete simple no soporta comodines de esa forma; necesitás usar [[ $var == foo* ]].
  • Confundir -a y -o con && y ||: dentro de [ ] los operadores lógicos son -a y -o; fuera de ellos, && y || actúan sobre el estado de salida de los comandos, no dentro de la prueba.
  • No quoteá variables vacías: si $var está sin definir, [ $var = "" ] genera un error "unary operator expected" porque el test ve dos argumentos seguidos. La solución es [ "$var" = "" ] o mejor [[ -z $var ]].
  • Usar [ [ ] ] con espacios extra: [[ $var -eq 5 ]] funciona, pero es raro; mantení un solo espacio después de [[ y antes de ]] para claridad.
  • Asumir que [[ $var < 10 ]] compara números: en realidad hace una comparación lexicográfica; para números usá -lt.
  • Olvidar el fi o el esac: genera errores de sintaxis difíciles de rastrear en scripts largos.

9. Conclusión

En este tutorial vimos cómo Bash provee tres formas de evaluar expresiones condicionales: el comando test, su sinónimo [ ] y la versión mejorada [[ ]]. Exploramos en detalle las comparaciones de números y cadenas, los operadores lógicos y cómo combinarlos en estructuras if‑elif‑else y case. A través de múltiples ejemplos con su salida esperada, viste cómo escribir scripts robustos y legibles.

Recordá aplicar las buenas prácticas: quoteá siempre las variables, preferí [[ ]] en Bash, usá los operadores correctos para cada tipo de dato y documentá la salida esperada. Evitando los errores más comunes, tus scripts serán más fáciles de mantener y menos propensos a fallos inesperados.

Con estos conocimientos ya podés tomar decisiones inteligentes en tus scripts de Bash, adaptando el flujo de ejecución a cualquier situación que se presente. ¡A programar!

Comentarios (0)

Sé el primero en comentar.

Dejá tu comentario