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 detest. 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; }