Curso de Shell Scripting

Cuando los scripts deben procesar grandes cantidades de datos o archivos, hacerlo de forma secuencial puede ser muy lento. Bash ofrece varias formas de ejecutar tareas en paralelo y optimizar los pipelines.


16.1. Problemas comunes en scripts lentos

  1. Procesar miles de archivos uno por uno en un bucle.
  2. Repetir tareas que podrían hacerse en paralelo.
  3. Usar pipelines ineficientes con muchas etapas innecesarias.
  4. Lanzar procesos externos dentro de bucles (for, while) sin necesidad.

👉 Objetivo: minimizar procesos y aprovechar la paralelización.


16.2. Ejecutar tareas en segundo plano con &

Se puede paralelizar fácilmente ejecutando comandos en background.

1#!/usr/bin/env bash
2
3echo "Procesando tareas..."
4sleep 3 &
5sleep 2 &
6sleep 1 &
7
8wait   # espera a que terminen todos
9echo "Tareas finalizadas"

Salida (tiempo total ≈ 3 s en vez de 6 s):

Procesando tareas...
Tareas finalizadas

16.3. Paralelismo controlado con xargs -P

xargs permite pasar una lista de elementos a un comando. La opción -P indica cuántos procesos ejecutar en paralelo.

Ejemplo: convertir imágenes a PNG en paralelo:

1ls *.jpg | xargs -n1 -P4 convert -resize 800x800 {} {.}.png
  • -n1 → pasa 1 argumento cada vez
  • -P4 → ejecuta 4 tareas en paralelo
  • {} → representa el archivo de entrada
  • {.} → nombre sin extensión

▸ Ejemplo simple: dormir en paralelo

1seq 1 5 | xargs -n1 -P3 bash -c 'echo "Procesando $1"; sleep $1' _

👉 Ejecuta 3 tareas en paralelo en lugar de una por una.


16.4. GNU parallel

Herramienta más potente y flexible que xargs. (A veces no viene instalada por defecto).

Instalación en Ubuntu/Debian:

1sudo apt install parallel

Ejemplo: redimensionar imágenes en paralelo:

1parallel convert {} {.}.png ::: *.jpg
  • ::: → separa el comando de la lista de argumentos.

▸ Controlar número de trabajos

1parallel -j 4 gzip {} ::: *.log

👉 Comprime archivos .log usando 4 procesos en paralelo.


▸ Pipeline con parallel

Ejemplo: procesar lista de URLs:

1cat urls.txt | parallel -j 5 "curl -s {} -o {#}.html"
  • -j 5 → 5 descargas simultáneas
  • {#} → índice del trabajo en ejecución

16.5. Sustitución de procesos <() y >()

Permite usar la salida de un comando como si fuera un archivo temporal, sin escribir al disco.

1diff <(sort archivo1.txt) <(sort archivo2.txt)

👉 Compara dos archivos ordenados al vuelo, sin archivos intermedios.


16.6. Optimizar pipelines

Cada | lanza un proceso adicional. Minimiza etapas innecesarias.

Ejemplo ineficiente:

1cat archivo.txt | grep "ERROR" | sort | uniq -c

Ejemplo optimizado:

1grep "ERROR" archivo.txt | sort | uniq -c

👉 Evitamos el uso innecesario de cat.


16.7. Medir el tiempo de ejecución

Puedes medir el tiempo total para evaluar mejoras:

1time ./mi_script.sh

O con el comando incorporado en scripts:

1START=$(date +%s)
2# ... código ...
3END=$(date +%s)
4echo "Tiempo total: $((END-START)) segundos"

16.8. Ejemplo integrador: procesamiento masivo de logs

Supón que tienes miles de archivos .log y quieres contar cuántas líneas con “ERROR” tiene cada uno y guardar el resultado en archivos separados.

1#!/usr/bin/env bash
2set -Eeuo pipefail
3
4mkdir -p resultados
5
6ls *.log | xargs -n1 -P4 bash -c '
7  archivo="$1"
8  grep -c "ERROR" "$archivo" > "resultados/${archivo%.log}_errores.txt"
9' _

👉 Procesa los logs en paralelo con 4 procesos simultáneos.


🏋️‍♂️ Ejercicio práctico 1

Crea un script procesa_urls.sh que:

  1. Lea una lista de URLs de urls.txt.
  2. Descargue cada página usando curl -s -o pagina_X.html.
  3. Use xargs -P4 o parallel para hacer varias descargas al mismo tiempo.
  4. Muestre el tiempo total de ejecución.

🏋️‍♂️ Ejercicio práctico 2

Crea un script compara_archivos.sh que:

  1. Compare pares de archivos listados en pares.txt (formato: archivo1 archivo2 por línea).
  2. Use diff con sustitución de procesos <() para comparar los archivos ordenados.
  3. Haga las comparaciones en paralelo con xargs -P2.

🏋️‍♂️ Ejercicio práctico 3

Crea un script comprime_logs.sh que:

  1. Encuentre todos los archivos .log de más de 5 MB.
  2. Los comprima en paralelo usando parallel -j 4 gzip {}.
  3. Muestre cuánto tiempo tardó todo el proceso.

✅ Buenas prácticas

  1. ✅ Paraleliza solo si las tareas son independientes entre sí.
  2. ✅ Ajusta el número de procesos (-P o -j) según los núcleos de la CPU.
  3. ✅ Usa sustitución de procesos para evitar archivos temporales.
  4. ✅ Optimiza los pipelines quitando comandos innecesarios.
  5. ✅ Mide el tiempo antes y después para comprobar mejoras reales.
  • Loading...