Operadores y comparaciones: test, [ ], [[ ]], numérico, cadenas, ficheros

Introducción

Las comparaciones son la base de toda lógica condicional en bash. Hay tres formas principales: el comando test, los corchetes simples [ ] y los dobles [[ ]]. Entender cuándo usar cada uno evita errores frecuentes.

test, [ ] y [[ ]]

  • test EXPRESIÓN — comando POSIX estándar. Compatible con cualquier shell.
  • [ EXPRESIÓN ] — sinónimo de test. Requiere espacios dentro. POSIX.
  • [[ EXPRESIÓN ]] — versión extendida de bash. Más potente y segura. No POSIX (solo bash/zsh).

# Las tres formas son equivalentes en lo básico:
test -f /etc/passwd
[ -f /etc/passwd ]
[[ -f /etc/passwd ]]
          

Preferir [[ ]] en scripts bash modernos: no necesita entrecomillar variables para evitar word splitting y soporta && y || directamente.

Comparación numérica


A=10
B=20

[ $A -eq $B ]   # equal: igual
[ $A -ne $B ]   # not equal: distinto
[ $A -lt $B ]   # less than: menor que
[ $A -le $B ]   # less or equal: menor o igual
[ $A -gt $B ]   # greater than: mayor que
[ $A -ge $B ]   # greater or equal: mayor o igual

# Con [[ ]] también se puede usar comparación aritmética
[[ $A -lt $B ]]
[[ $((A + 5)) -eq 15 ]]
          

Comparación de cadenas


NOMBRE="Juan"

[ "$NOMBRE" = "Juan" ]     # igual (POSIX, también funciona ==)
[ "$NOMBRE" != "Pedro" ]   # distinto
[ -z "$NOMBRE" ]           # -z: cadena vacía (zero length)
[ -n "$NOMBRE" ]           # -n: cadena no vacía (non-zero length)

# Con [[ ]] se puede usar == con globbing y =~ con regex
[[ "$NOMBRE" == "Ju*" ]]          # glob: empieza por Ju
[[ "$NOMBRE" =~ ^J[ua]+n$ ]]      # regex: coincide con el patrón
          

Importante: con [ ] siempre entrecomillar las variables de cadena: [ "$VAR" = "valor" ]. Sin comillas, si $VAR está vacía, el comando recibe menos argumentos de los esperados y falla.

Comprobaciones sobre ficheros y directorios


[ -e RUTA ]    # existe (cualquier tipo)
[ -f RUTA ]    # existe y es un fichero regular
[ -d RUTA ]    # existe y es un directorio
[ -L RUTA ]    # existe y es un enlace simbólico
[ -r RUTA ]    # existe y tiene permiso de lectura
[ -w RUTA ]    # existe y tiene permiso de escritura
[ -x RUTA ]    # existe y tiene permiso de ejecución
[ -s RUTA ]    # existe y no está vacío (size > 0)
[ -b RUTA ]    # es un dispositivo de bloque
[ -c RUTA ]    # es un dispositivo de caracteres
[ RUTA1 -nt RUTA2 ]  # RUTA1 es más nuevo que RUTA2 (newer than)
[ RUTA1 -ot RUTA2 ]  # RUTA1 es más antiguo que RUTA2 (older than)
          

Ejemplos prácticos:


if [ ! -d "/backup" ]; then
    mkdir -p /backup
fi

if [ -f "$FICHERO" ] && [ -r "$FICHERO" ]; then
    echo "El fichero existe y se puede leer"
fi
          

Operadores lógicos


# Con [ ] — usar -a (AND) y -o (OR) o combinar con && y ||
[ $A -gt 0 -a $A -lt 100 ]       # -a: AND dentro de [ ]
[ $A -lt 0 -o $A -gt 100 ]       # -o: OR dentro de [ ]
[ $A -gt 0 ] && [ $A -lt 100 ]   # AND con dos bloques (más claro)
[ $A -lt 0 ] || [ $A -gt 100 ]   # OR con dos bloques

# Con [[ ]] — usar && y || directamente
[[ $A -gt 0 && $A -lt 100 ]]
[[ $A -lt 0 || $A -gt 100 ]]

# Negación
[ ! -f /etc/passwd ]
[[ ! -d /tmp/cache ]]
          

&& y || como condicionales inline

Una forma compacta de ejecutar comandos condicionalmente sin necesidad de if:


# Ejecutar B solo si A tiene éxito (exit 0)
mkdir /backup && echo "Directorio creado"

# Ejecutar B solo si A falla (exit != 0)
ping -c1 servidor || echo "El servidor no responde"

# Combinados: si A falla, ejecutar B y salir
[ -d "$DIRECTORIO" ] || { echo "El directorio no existe" >&2; exit 1; }
          

Regla práctica: usar [[ ]] en bash moderno para mayor seguridad y capacidades; reservar [ ] para scripts que deban ser compatibles con /bin/sh POSIX.

Condicionales: if, elif, else, case

Índice de la sección

Índice del curso