Condicionales en Bash: test, [ ] y [[ ]] explicados con ejemplos prácticos
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
- Siempre quoteá las variables dentro de los corchetes cuando haya riesgo de que contengan espacios o estén vacías. Ejemplo:
[[ "$var" == "valor" ]]. - Preferí
[[ ]]sobre[ ]en scripts Bash por su mejor manejo de operadores lógicos y patrones. - Usá los operadores de prueba adecuados para cada tipo de dato:
-eq,-ltetc. para números;=,!=,-z,-npara cadenas. - Evité la mezcla de estilos: no mezclés
-a/-ocon&&/||dentro del mismo[ ]porque la precedencia puede confundir. - Indentá claramente los bloques
if,elif,elseycasepara mejorar la legibilidad. - Comentá las condiciones complejas para que futuros lectores (o vos mismo en el futuro) comprendan rápidamente el intent.
- Probá los scripts con
set -euo pipefailal inicio para que errores en variables no definidas o en comandos fallen temprano. - Usá
[[ $var == *pat* ]]para coincidencias de subcadenas en lugar de expresiones regulares cuando sea suficiente; es más rápido y legible. - Cuando necesité comparaciones de punto flotante, recordá que Bash no soporta floats nativamente; recurrí a
bcoawk. - 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
-ay-ocon&&y||: dentro de[ ]los operadores lógicos son-ay-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
$varestá 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
fio elesac: 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!
DUGLAS MORENO
Comentarios (0)
Sé el primero en comentar.