Control con break y continue

Controla el flujo de tus bucles con precisión quirúrgica

Módulo 3 ⏱️ 25-30 min 🎛️ Control 🚪 Flujo 📚 Intermedio

Control de Flujo en Bucles

En ocasiones, necesitamos más control sobre cómo se ejecutan nuestros bucles. Bash proporciona dos comandos fundamentales para este propósito: break y continue. Estas herramientas nos permiten modificar el comportamiento normal de los bucles para crear lógica más sofisticada y eficiente.

Comandos de Control de Bucles

BREAK

Función: Termina completamente el bucle actual y continúa con el código después del bucle.

Uso: Cuando se cumple una condición que hace innecesario continuar con las iteraciones.

CONTINUE

Función: Salta el resto de la iteración actual y pasa directamente a la siguiente.

Uso: Cuando quieres omitir ciertos elementos pero continuar con el bucle.

Flujo de Control Visual
Inicio Bucle
Condición
Código
BREAK
Sale del bucle
CONTINUE
Siguiente iteración

El Comando BREAK

El comando break termina inmediatamente el bucle más interno y continúa la ejecución con la primera línea después del bucle.

Sintaxis y Uso Básico

Estructura básica con break Copiar
for variable in lista
do
    # código antes de la condición
    if [ condición ]
    then
        break  # Sale completamente del bucle
    fi
    # código que se ejecuta si no se hace break
done
# El programa continúa aquí después del break

Ejemplos Prácticos

Ejemplo 1: Buscar archivo específico Copiar
#!/bin/bash
# Buscar un archivo específico y parar cuando se encuentre
archivo_buscado="config.txt"
encontrado=false

echo "Buscando $archivo_buscado en directorios..."

for directorio in /etc /home /var /tmp
do
    echo "Buscando en: $directorio"
    
    if [ -f "$directorio/$archivo_buscado" ]; then
        echo "¡Archivo encontrado en $directorio/$archivo_buscado!"
        encontrado=true
        break  # Ya lo encontramos, no necesitamos seguir buscando
    fi
    
    echo "No encontrado en $directorio"
done

if [ "$encontrado" = true ]; then
    echo "Búsqueda completada exitosamente"
else
    echo "Archivo no encontrado en ningún directorio"
fi
$ ./buscar_archivo.sh
Buscando config.txt en directorios...
Buscando en: /etc
No encontrado en /etc
Buscando en: /home
¡Archivo encontrado en /home/config.txt!
Búsqueda completada exitosamente
Ejemplo 2: Validación de entrada Copiar
#!/bin/bash
# Pedir entrada válida al usuario
while true
do
    echo -n "Ingresa un número entre 1 y 10 (o 'q' para salir): "
    read entrada
    
    # Verificar si el usuario quiere salir
    if [ "$entrada" = "q" ] || [ "$entrada" = "Q" ]; then
        echo "¡Hasta luego!"
        break
    fi
    
    # Verificar si es un número válido
    if [[ "$entrada" =~ ^[0-9]+$ ]] && [ "$entrada" -ge 1 ] && [ "$entrada" -le 10 ]; then
        echo "¡Excelente! Elegiste el número $entrada"
        break
    else
        echo "Error: Debes ingresar un número entre 1 y 10"
    fi
done

echo "Programa terminado"
Consejo Pro

Usa break para evitar procesamiento innecesario. Es especialmente útil en búsquedas donde una vez que encuentras lo que buscas, no necesitas continuar.

El Comando CONTINUE

El comando continue omite el resto de la iteración actual y pasa inmediatamente a la siguiente iteración del bucle.

Sintaxis y Uso Básico

Estructura básica con continue Copiar
for variable in lista
do
    if [ condición_de_omisión ]
    then
        continue  # Salta a la siguiente iteración
    fi
    # código que se ejecuta solo si no se hace continue
done

Ejemplos Prácticos

Ejemplo 1: Procesar solo archivos válidos Copiar
#!/bin/bash
# Procesar solo archivos .txt que no estén vacíos
echo "Procesando archivos de texto..."

for archivo in *.txt
do
    # Omitir si el archivo no existe (caso de no hay archivos .txt)
    if [ ! -f "$archivo" ]; then
        continue
    fi
    
    # Omitir archivos vacíos
    if [ ! -s "$archivo" ]; then
        echo "Omitiendo $archivo (archivo vacío)"
        continue
    fi
    
    # Omitir archivos de respaldo (que terminen en .bak.txt)
    if [[ "$archivo" == *.bak.txt ]]; then
        echo "Omitiendo $archivo (archivo de respaldo)"
        continue
    fi
    
    # Procesar archivo válido
    lineas=$(wc -l < "$archivo")
    palabras=$(wc -w < "$archivo")
    echo "Procesando $archivo: $lineas líneas, $palabras palabras"
done

echo "Procesamiento completado"
$ ./procesar_textos.sh
Procesando archivos de texto...
Omitiendo temporal.txt (archivo vacío)
Omitiendo backup.bak.txt (archivo de respaldo)
Procesando documento.txt: 25 líneas, 180 palabras
Procesando notas.txt: 15 líneas, 95 palabras
Procesamiento completado
Ejemplo 2: Procesar solo números pares Copiar
#!/bin/bash
# Procesar solo números pares del 1 al 20
echo "Procesando números pares del 1 al 20:"

for numero in {1..20}
do
    # Omitir números impares
    if [ $((numero % 2)) -ne 0 ]; then
        continue
    fi
    
    # Procesar solo números pares
    cuadrado=$((numero * numero))
    echo "El cuadrado de $numero es $cuadrado"
done
Ventaja del continue

El comando continue te permite filtrar elementos sin necesidad de anidar múltiples estructuras if, manteniendo tu código más limpio y legible.

Break y Continue en Bucles Anidados

Cuando trabajas con bucles anidados, break y continue afectan solo al bucle más interno por defecto. Sin embargo, puedes especificar cuántos niveles quieres afectar.

Sintaxis con Niveles

Break y continue con niveles Copiar
# break n    - Sale de n niveles de bucle
# continue n - Continúa n niveles de bucle hacia arriba

for i in {1..3}
do
    for j in {1..3}
    do
        if [ condición ]; then
            break 2    # Sale de ambos bucles (2 niveles)
        fi
        
        if [ otra_condición ]; then
            continue 2 # Continúa con la siguiente iteración del bucle externo
        fi
    done
done
Ejemplo: Matriz de búsqueda Copiar
#!/bin/bash
# Buscar un número específico en una matriz
numero_buscado=7
encontrado=false

echo "Buscando el número $numero_buscado en matriz 3x3:"

for fila in 1 2 3
do
    for columna in 1 2 3
    do
        # Simular valores de matriz
        valor=$(((fila - 1) * 3 + columna))
        echo -n "Revisando posición [$fila,$columna] = $valor ... "
        
        if [ $valor -eq $numero_buscado ]; then
            echo "¡ENCONTRADO!"
            encontrado=true
            break 2  # Sale de ambos bucles
        else
            echo "no es"
        fi
    done
done

if [ "$encontrado" = true ]; then
    echo "Búsqueda completada: número encontrado"
else
    echo "Búsqueda completada: número no encontrado"
fi
$ ./buscar_matriz.sh
Buscando el número 7 en matriz 3x3:
Revisando posición [1,1] = 1 ... no es
Revisando posición [1,2] = 2 ... no es
Revisando posición [1,3] = 3 ... no es
Revisando posición [2,1] = 4 ... no es
Revisando posición [2,2] = 5 ... no es
Revisando posición [2,3] = 6 ... no es
Revisando posición [3,1] = 7 ... ¡ENCONTRADO!
Búsqueda completada: número encontrado

Casos de Uso Avanzados

Validación de Datos
Procesar lista de emails Copiar
#!/bin/bash
# Validar lista de emails
emails=("[email protected]" "invalid-email" "[email protected]" "" "[email protected]")

echo "Validando emails:"
emails_validos=0

for email in "${emails[@]}"
do
    # Omitir emails vacíos
    if [ -z "$email" ]; then
        echo "Omitiendo email vacío"
        continue
    fi
    
    # Validación básica (contiene @ y .)
    if [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
        echo "✓ Email válido: $email"
        ((emails_validos++))
    else
        echo "✗ Email inválido: $email"
        continue
    fi
done

echo "Total de emails válidos: $emails_validos"
Descarga con Reintentos
Descargar con reintentos Copiar
#!/bin/bash
# Descargar archivos con reintentos
urls=("http://example.com/file1.txt" "http://example.com/file2.txt")

for url in "${urls[@]}"
do
    archivo=$(basename "$url")
    echo "Descargando: $archivo"
    
    # Intentar descargar hasta 3 veces
    for intento in {1..3}
    do
        if curl -f -o "$archivo" "$url"; then
            echo "✓ Descarga exitosa en intento $intento"
            break  # Éxito, pasar al siguiente archivo
        else
            echo "✗ Intento $intento fallido"
            if [ $intento -eq 3 ]; then
                echo "Error: No se pudo descargar $archivo"
            else
                echo "Reintentando en 2 segundos..."
                sleep 2
            fi
        fi
    done
done

Errores Comunes y Mejores Prácticas

Errores Comunes
  • Break fuera de bucle: Usar break fuera de un bucle causa error
  • Nivel incorrecto: break 5 cuando solo hay 2 niveles
  • Lógica confusa: Usar continue cuando se necesita break
  • Bucles infinitos: Continue que impide que cambie la condición
Mejores Prácticas
  • Usa nombres descriptivos: Variables que indican el estado
  • Comenta la lógica: Explica por qué usas break/continue
  • Mantén simplicidad: Evita demasiados niveles anidados
  • Valida condiciones: Asegúrate de que las condiciones pueden cambiar
Ejemplo de buenas prácticas Copiar
#!/bin/bash
# Ejemplo con buenas prácticas
archivos_procesados=0
archivos_omitidos=0

for archivo in *.log
do
    # Verificar que el archivo existe (globbing puede no encontrar archivos)
    if [ ! -f "$archivo" ]; then
        echo "No hay archivos .log para procesar"
        break
    fi
    
    # Omitir archivos de sistema (empiezan con punto)
    if [[ "$archivo" == .* ]]; then
        echo "Omitiendo archivo de sistema: $archivo"
        ((archivos_omitidos++))
        continue
    fi
    
    # Omitir archivos muy grandes (>100MB)
    if [ $(stat -f%z "$archivo" 2>/dev/null || stat -c%s "$archivo" 2>/dev/null) -gt 104857600 ]; then
        echo "Omitiendo archivo muy grande: $archivo"
        ((archivos_omitidos++))
        continue
    fi
    
    # Procesar archivo válido
    echo "Procesando: $archivo"
    # Aquí iría la lógica de procesamiento
    ((archivos_procesados++))
done

echo "Resumen:"
echo "- Archivos procesados: $archivos_procesados"
echo "- Archivos omitidos: $archivos_omitidos"

Ejercicios Prácticos

Ejercicio 1: Calculadora de Promedios

Crea un script que calcule promedios omitiendo valores inválidos:

calculadora_promedio.sh Copiar
#!/bin/bash
# Calcular promedio de números válidos
numeros=("10" "abc" "20" "" "30" "-5" "40")
suma=0
contador=0

echo "Calculando promedio de números válidos:"

for numero in "${numeros[@]}"
do
    # Omitir strings vacíos
    if [ -z "$numero" ]; then
        echo "Omitiendo valor vacío"
        continue
    fi
    
    # Verificar si es un número
    if ! [[ "$numero" =~ ^-?[0-9]+$ ]]; then
        echo "Omitiendo valor no numérico: $numero"
        continue
    fi
    
    # Omitir números negativos (según requisitos del ejemplo)
    if [ "$numero" -lt 0 ]; then
        echo "Omitiendo número negativo: $numero"
        continue
    fi
    
    # Procesar número válido
    echo "Usando número: $numero"
    suma=$((suma + numero))
    ((contador++))
done

if [ $contador -gt 0 ]; then
    promedio=$((suma / contador))
    echo "Promedio de $contador números: $promedio"
else
    echo "No se encontraron números válidos"
fi
Ejercicio 2: Generador de Contraseñas

Crea un generador que produzca contraseñas hasta encontrar una que cumpla criterios específicos:

generar_password.sh Copiar
#!/bin/bash
# Generar contraseña que cumpla criterios específicos
intentos=0
max_intentos=100

echo "Generando contraseña segura..."

while [ $intentos -lt $max_intentos ]
do
    ((intentos++))
    
    # Generar contraseña aleatoria de 12 caracteres
    password=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 12)
    
    echo "Intento $intentos: $password"
    
    # Verificar longitud mínima
    if [ ${#password} -lt 8 ]; then
        echo "  ✗ Muy corta"
        continue
    fi
    
    # Verificar que tenga al menos una mayúscula
    if ! [[ "$password" =~ [A-Z] ]]; then
        echo "  ✗ Sin mayúsculas"
        continue
    fi
    
    # Verificar que tenga al menos una minúscula
    if ! [[ "$password" =~ [a-z] ]]; then
        echo "  ✗ Sin minúsculas"
        continue
    fi
    
    # Verificar que tenga al menos un número
    if ! [[ "$password" =~ [0-9] ]]; then
        echo "  ✗ Sin números"
        continue
    fi
    
    # Si llegamos aquí, la contraseña cumple todos los criterios
    echo "  ✓ ¡Contraseña válida generada en $intentos intentos!"
    echo "  Contraseña final: $password"
    break
done

if [ $intentos -eq $max_intentos ]; then
    echo "No se pudo generar una contraseña válida en $max_intentos intentos"
    exit 1
fi