Juan Diego Andrés PRADA··RAMÍREZ Entrar
Lección 5 de 7

Scripting en Bash

¿Qué es?

Un script es un archivo de texto que reúne varios comandos para que el shell los ejecute en orden, de arriba abajo, de un solo gesto. Es la diferencia entre teclear la misma secuencia cada día y escribirla una sola vez para usarla siempre. En esta lección usamos Bash de forma explícita, porque está presente en casi todas las máquinas y es el estándar para escribir scripts. Aquí dejas de dar órdenes sueltas y empiezas a programar la terminal.

¿Cómo funciona?

Un script empieza con un shebang (#!/usr/bin/env bash) que indica con qué intérprete correrlo, seguido de set -euo pipefail, un cinturón de seguridad que detiene la ejecución ante errores. A partir de ahí combinas variables ("$NOMBRE"), argumentos que recibe desde la terminal ($1, $@, $#), condicionales con if [[ ... ]], bucles for y while, y funciones que agrupan lógica reutilizable. El patrón profesional es validar las entradas antes de actuar, escribir los errores a stderr y salir con un código distinto de cero cuando algo falla.

¿Para qué sirve?

Aquí construyes la materia prima de tu proyecto final «Tu kit de automatización personal»: pasas de comandos sueltos a programas propios que hacen el trabajo por ti. El ejemplo guiado es un script de respaldo con fecha, exactamente el tipo de pieza reutilizable que poblará tu kit. Cada automatización que diseñes en el resto del curso, desde renombrar archivos hasta procesar registros, nace de las estructuras que aprendes en esta lección.

Un script es un archivo de texto con comandos que el shell ejecuta de arriba abajo. Es la diferencia entre teclear lo mismo cada día y escribirlo una vez para siempre. Aquí construyes la materia prima de tu proyecto final: el kit de automatización personal.

Usamos Bash explícitamente (no Zsh) para los scripts porque está en todas partes y es el estándar. Por eso el shebang será #!/usr/bin/env bash: encuentra el bash del sistema sin importar dónde esté instalado.

El esqueleto de todo script

#!/usr/bin/env bash
set -euo pipefail # cinturón de seguridad (lo explicamos abajo)

echo "Empezando..."

set -euo pipefail es una línea casi obligatoria:

  • -e: si un comando falla, el script se detiene (no sigue como si nada).
  • -u: usar una variable no definida es un error (atrapa erratas).
  • -o pipefail: si una etapa de una tubería falla, la tubería falla.

Sin set -e, un script puede seguir ejecutándose después de un error grave y dejar todo a medias. Sin set -u, una errata como $ruta en vez de $RUTA se evalúa como vacío y rm -rf "$ruta/" se vuelve rm -rf /. Estas tres opciones evitan accidentes reales.

Variables y argumentos

#!/usr/bin/env bash
set -euo pipefail

NOMBRE="Ana" # sin espacios alrededor del =
echo "Hola, $NOMBRE"
echo "Hoy es: $(date +%F)" # $(...) captura la salida de un comando

# Argumentos que recibe el script desde la terminal:
echo "Primer argumento: $1"
echo "Todos: $@"
echo "Cuántos: $#"

Siempre entrecomilla tus variables: "$NOMBRE", no $NOMBRE. Sin comillas, un valor con espacios se parte en varios argumentos y los nombres de archivo con espacios rompen el script.

Condicionales

#!/usr/bin/env bash
set -euo pipefail

ARCHIVO="datos.txt"

if [[ -f "$ARCHIVO" ]]; then
 echo "El archivo existe."
elif [[ -d "$ARCHIVO" ]]; then
 echo "Es un directorio, no un archivo."
else
 echo "No existe."
fi

Pruebas útiles dentro de [[ ... ]]:

[[ -f ruta ]] # ¿es un archivo regular?
[[ -d ruta ]] # ¿es un directorio?
[[ -z "$VAR" ]] # ¿la variable está vacía?
[[ -n "$VAR" ]] # ¿tiene contenido?
[[ "$a" == "$b" ]] # comparar textos
[[ "$n" -gt 10 ]] # comparar números: -gt -lt -ge -le -eq -ne

Usa [[ ... ]] (doble corchete, propio de Bash) en vez de [ ... ]. Es más seguro con espacios y variables vacías.

Bucles

# Recorrer archivos
for archivo in *.txt; do
 echo "Procesando $archivo"
done

# Recorrer una lista
for color in rojo verde azul; do
 echo "$color"
done

# Mientras se cumpla una condición
contador=1
while [[ $contador -le 3 ]]; do
 echo "Vuelta $contador"
 contador=$((contador + 1))
done

Funciones

saludar() {
 local nombre="$1" # 'local' limita la variable a la función
 echo "Hola, $nombre"
}

saludar "Mundo"

Ejemplo guiado: respaldo con fecha

Construyamos un script real: copia una carpeta a un respaldo con la fecha en el nombre. Es la pieza estrella de muchos kits de automatización.

#!/usr/bin/env bash
set -euo pipefail

# 1. Validar que nos pasaron la carpeta a respaldar
if [[ $# -ne 1 ]]; then
 echo "Uso: $0 <carpeta-a-respaldar>" >&2
 exit 1
fi

ORIGEN="$1"

# 2. Validar que el origen existe y es un directorio
if [[ ! -d "$ORIGEN" ]]; then
 echo "Error: '$ORIGEN' no es un directorio." >&2
 exit 1
fi

# 3. Construir el nombre del destino con fecha y hora
FECHA="$(date +%Y-%m-%d_%H%M%S)"
DESTINO="${ORIGEN%/}_backup_$FECHA"

# 4. Copiar y avisar
cp -r "$ORIGEN" "$DESTINO"
echo "Respaldo creado en: $DESTINO"

Pruébalo paso a paso:

# Guarda el código como respaldo.sh y dale permiso
chmod u+x respaldo.sh

# Sin argumentos: muestra el uso y sale con error
./respaldo.sh
# Uso: ./respaldo.sh <carpeta-a-respaldar>

# Con una carpeta real
mkdir -p prueba && touch prueba/a.txt
./respaldo.sh prueba
# Respaldo creado en: prueba_backup_2026-06-22_101500

Fíjate en el patrón profesional: valida las entradas antes de actuar, escribe los errores a >&2 (stderr) y sal con exit 1 cuando algo falla. Así tus scripts se comportan bien si los encadenas con otros. ${ORIGEN%/} quita una barra final sobrante: detalle pequeño que evita nombres feos.

Antes de añadir borrado o sobreescritura a un script, pruébalo con echo delante del comando peligroso (un "dry run"): así ves qué haría sin que lo haga de verdad.

Tech English: script (guion), shebang (la línea #!), argument (argumento), flag (opción), exit code (código de salida: 0 = éxito), dry run (ensayo sin ejecutar), loop (bucle), condition (condición).

Ejercicios

  1. Diseña la lógica de un renombrador. Sin programarlo aún, escribe en pseudocódigo (o en español estructurado) un script que recorra todos los .jpeg de una carpeta y los renombre a .jpg. Indica qué validaciones pondrías al inicio, qué bucle usarías y cómo evitarías sobreescribir un archivo que ya exista con el nuevo nombre. Justifica cada decisión.

  2. Audita un script peligroso. Te dan este fragmento: for f in $(ls); do rm $f; done. Identifica al menos tres problemas (pista: comillas, set, parseo de ls, falta de validación) y reescríbelo de forma segura explicando cada cambio. No basta con que "funcione": debe ser robusto ante nombres con espacios y ante una carpeta vacía.

Tu progreso se guarda en este navegador. Inicia sesión para guardarlo en tu cuenta y verlo desde cualquier dispositivo.