Operadores Condicionales y Lógicos en Bash: Explorando `[[ ]]` vs `[ ]`

Los scripts de shell a menudo requieren la capacidad de tomar decisiones basadas en condiciones. Bash ofrece varias construcciones para evaluar expresiones, siendo las más comunes el comando test y sus alias [ ], así como la expresión extendida [[ ]]. Comprender las diferencias y capacidades de cada una es fundamental para escribir scripts robustos y eficientes.

Evaluación de Archivos y Directorios

Bash proporciona operadores para verificar la existencia y el tipo de archivos y directorios en el sistema de archivos:

  • -f <ruta>: Verdadero si la ruta especificada es un archivo regular existente.
  • -d <ruta>: Verdadero si la ruta especificada es un directorio existente.
  • -e <ruta>: Verdadero si la ruta existe (sea archivo, directorio, enlace simbólico, etc.).
  • -b <ruta>: Verdadero si la ruta es un dispositivo de bloque.
  • -c <ruta>: Verdadero si la ruta es un dispositivo de caracteres.
  • -S <ruta>: Verdadero si la ruta es un socket.
  • -L <ruta>: Verdadero si la ruta es un enlace simbólico.
  • -p <ruta>: Verdadero si la ruta es una tubería (FIFO).

Atributos de Archivos

También es posible verificar los permisos y otras propiedades de un archivo:

  • -r <archivo>: Verdadero si el archivo es legible por el usuario actual.
  • -w <archivo>: Verdadero si el archivo es escribible por el usuario actual.
  • -x <archivo>: Verdadero si el archivo es ejecutable por el usuario actual.
  • -s <archivo>: Verdadero si el archivo existe y su tamaño es mayor que cero (no vacío).
  • -u <archivo>: Verdadero si el archivo tiene el bit SUID activado.
  • -g <archivo>: Verdadero si el archivo tiene el bit SGID activado.
  • -k <archivo>: Verdadero si el archivo tiene el bit pegajoso (sticky bit) activado.

Comparación entre Archivos

Podemos comparar la antigüedad o la identidad de dos archivos:

  • <archivo1> -nt <archivo2>: Verdadero si <archivo1> es más reciente que <archivo2>.
  • <archivo1> -ot <archivo2>: Verdadero si <archivo1> es más antiguo que <archivo2>.
  • <archivo1> -ef <archivo2>: Verdadero si <archivo1> y <archivo2> son el mismo archivo (ej. enlaces duros).
# Ejemplo de comparación de archivos
touch archivo_viejo.txt
sleep 1
touch archivo_nuevo.txt

if [ "archivo_nuevo.txt" -nt "archivo_viejo.txt" ]; then
    echo "archivo_nuevo.txt es más reciente."
fi

# Limpieza
rm archivo_viejo.txt archivo_nuevo.txt

Operadores de Comparación y Lógicos

Las expresiones condicionales utilizan diversos operadores para comparar valores y combinar condiciones:

Comparación de Cadenas y Números Enteros:

  • = (o == para [[ ]]): Igual a. Se usa para cadenas en [ ] y cadenas/patrones en [[ ]].
  • !=: Diferente de. Se usa para cadenas en [ ] y cadenas/patrones en [[ ]].
  • <: Menor que (lexicográfico para cadenas en [[ ]]; requiere escape como \< para cadenas en [ ]).
  • >: Mayor que (lexicográfico para cadenas en [[ ]]; requiere escape como \> para cadenas en [ ]).
  • -eq: Igual a (numérico).
  • -ne: Diferente de (numérico).
  • -lt: Menor que (numérico).
  • -gt: Mayor que (numérico).
  • -le: Menor o igual que (numérico).
  • -ge: Mayor o igual que (numérico).
  • -z <cadena>: Verdadero si la cadena está vacía (longitud cero).
  • -n <cadena>: Verdadero si la cadena no está vacía (longitud mayor que cero).

Operadores Lógicos Booleanos:

  • -a: AND lógico. Usado en test y [ ].
  • -o: OR lógico. Usado en test y [ ].
  • &&: AND lógico. Usado en [[ ]] y como operador de control en la línea de comandos.
  • ||: OR lógico. Usado en [[ ]] y como operador de control en la línea de comandos.

El Comando test

El comando test evalúa una expresión y devuelve un estado de salida de 0 (verdadero) o 1 (falso). Es la base de todas las demás construcciones condicionales en scripts de shell.

# Ejemplos con el comando test
test -f /etc/passwd && echo "El archivo /etc/passwd existe."
test 5 -eq 5 && echo "5 es igual a 5."

valor=10
if test $valor -gt 0; then
    echo "El valor es positivo."
fi

Es crucial separar los operadores y los operandos con espacios. Por ejemplo, test 1=1 es incorrecto, debe ser test 1 = 1.

Expresiones Condicionales con Corchetes Simples \[ \]

La sintaxis [ expresión ] es un alias para el comando test. Hereda todas sus reglas y limtiaciones. Al igual que con test, cada elemento (operador, operando) debe estar separado por un espacio.

# Ejemplos con [ ]
[ 10 -eq 10 ] && echo "Igualdad numérica confirmada."

# Comparación de cadenas con operadores relacionales (<, >) requiere escape
# De lo contrario, Bash interpreta < y > como operadores de redirección de E/S.
cadena1="manzana"
cadena2="pera"
[ "$cadena1" \< "$cadena2" ] && echo "'manzana' es menor que 'pera' (lexicográficamente)."

# Uso de operadores lógicos -a (AND) y -o (OR)
numero=7
[ $numero -gt 5 -a $numero -lt 10 ] && echo "$numero está entre 5 y 10."

# Errores comunes:
# [ 2 < 1 ] && echo "Esto fallará por redirección de E/S"
# [ 1 -eq 1 && 2 -eq 2 ] && echo "Esto es sintaxis incorrecta para [ ]"

Dentro de [ ], los operadores <, >, && y || no se comportan como operadores de comparación o lógicos. < y > se interpretan como redirecciones de entrada/salida, y &&/|| como operadores de control de flujo. Para comparaciones de cadenas, < y > deben ser escapados (\<, \>), y para lógica booleana se usan -a y -o.

Expresiones Condicionales con Doble Corchete \[\[ \]\]

La construcción [[ expresión ]] es una característica extendida de Bash que ofrece mayor flexibilidad y potencia. Es un "comando" compuesto, no un comando regular, lo que significa que no se somete a la expansión de palabras y tiene un comportamiento especial.

# Ejemplos con [[ ]]
[[ 20 -eq 20 ]] && echo "Igualdad numérica extendida."

# < y > funcionan directamente para comparación lexicográfica (cadenas) o numérica (si son números)
[[ "abc" < "xyz" ]] && echo "'abc' es menor que 'xyz'."
[[ 15 < 25 ]] && echo "15 es menor que 25 (numéricamente)."

# Soporte directo para && (AND) y || (OR) lógicos
edad=30
[[ $edad -gt 18 && $edad -lt 65 ]] && echo "Edad en rango laboral."

# Importante: [[ ]] no utiliza -a ni -o para la lógica booleana
# [[ $edad -gt 18 -a $edad -lt 65 ]] # Esto generaría un error de sintaxis en [[ ]]

Diferencias Clave entre \[\[ \]\] y \[ \]

  1. Operadores Lógicos:

    [ ] requiere -a para AND y -o para OR.

    [[ ]] utiliza && para AND y || para OR, similar a la sintaxis C/Java.

    # Comprobación de existencia de un archivo Y si es ejecutable
    archivo="/bin/ls"
    
    # Usando [ ]
    [ -f "$archivo" -a -x "$archivo" ] && echo "El archivo existe y es ejecutable (con [ ])."
    
    # Usando [[ ]]
    [[ -f "$archivo" && -x "$archivo" ]] && echo "El archivo existe y es ejecutable (con [[ ]])."
    
    
  2. Redirección vs. Comparación:

    En [ ], los operadores < y > deben ser escapados (\<, \>) para realizar comparaciones de cadenas, ya que de otro modo Bash los interpreta como operadores de redirección de E/S.

    En [[ ]], < y > no necesitan ser escapados y realizan comparaciones lexicográficas de cadenas (o numéricas si los operandos son números).

    # Comparación de cadenas "beta" con "alpha"
    val_beta="beta"
    val_alpha="alpha"
    
    # Usando [ ] con escape
    [ "$val_beta" \> "$val_alpha" ] && echo "'beta' es mayor que 'alpha' (con [ ] y escape)."
    
    # Usando [[ ]] sin escape
    [[ "$val_beta" > "$val_alpha" ]] && echo "'beta' es mayor que 'alpha' (con [[ ]] sin escape)."
    
    
  3. Expansión Aritmética:

    [ ] no realiza evaluación aritmética directa. Para ello, se necesita una expansión aritmética explícita ($((...))).

    [[ ]] realiza la expansión aritmética dentro de sus expresiones.

    # Evaluar si 10 + 5 es igual a 15
    resultado_suma="10+5"
    
    # Usando [ ] - requiere expansión explícita
    [ $((10+5)) -eq 15 ] && echo "Suma correcta con [ ] y expansión."
    
    # Usando [[ ]] - evaluación automática
    [[ 10+5 -eq 15 ]] && echo "Suma correcta con [[ ]] y evaluación automática."
    
    
  4. Coincidencia de Patrones (Regex):

    [[ ]] permite la coincidencia de patrones (expresiones regulares extendidas) usando el operador =~, o patrones tipo glob (wildcards) con = o ==.

    [ ] solo admite la coincidencia de cadenas literales o patrones tipo glob simples (*, ?) si la shell expande los wildcards antes de que [ ] los reciba, lo cual puede ser inconsistente.

    # Verificar si un nombre de archivo termina en .log
    nombre_archivo="mi_log_del_dia.log"
    
    # Usando [[ ]] para coincidencia de patrón glob
    [[ "$nombre_archivo" == *.log ]] && echo "El archivo termina en .log (con [[ ]] glob)."
    
    # Usando [[ ]] para expresión regular
    [[ "$nombre_archivo" =~ \.log$ ]] && echo "El archivo termina en .log (con [[ ]] regex)."
    
    # [ ] no soporta coincidencias de patrones de esta manera directamente
    # [ "$nombre_archivo" == *.log ] # Esto no funcionará como se espera para coincidencia de patrón.
    # [ "$nombre_archivo" =~ \.log$ ] # Esto causará un error de sintaxis.
    
    

Etiquetas: bash shell scripting Operadores Lógicos Condicionales Test Command

Publicado el 10-26 06:47