Bash scripting es, sin exageración, la habilidad más práctica y rentable que puedes adquirir como usuario o administrador de Linux. Con un simple archivo de texto, puedes automatizar copias de seguridad que se ejecuten cada noche, procesar miles de archivos en segundos, monitorizar servidores y crear herramientas personalizadas que ahorren horas de trabajo manual. Esta guía te lleva desde los fundamentos absolutos hasta la escritura de scripts profesionales con ejemplos reales, diagramas, ejercicios resueltos y un proyecto integrador completo que podrás adaptar a tu propio entorno de trabajo.
🐚 ¿Qué es Bash?
Bash (acrónimo recursivo de Bourne Again SHell) es el intérprete de comandos por defecto en la inmensa mayoría de distribuciones Linux y en macOS hasta Catalina (2019). Fue creado por Brian Fox en 1989 dentro del proyecto GNU de Richard Stallman, como un reemplazo libre y mejorado del Bourne Shell (sh) original de Unix. Hoy, cuando abres una terminal en Ubuntu, Debian, Mint, Fedora o CentOS, estás interactuando directamente con Bash.
Pero Bash no es solo un intérprete interactivo: es también un lenguaje de programación completo. Soporta variables, condicionales, bucles, funciones, arrays, redirecciones, pipes y expansiones. Un script de Bash es simplemente un archivo de texto plano que contiene una secuencia de estos comandos. En lugar de escribir cada instrucción manualmente en la terminal, los guardas en un archivo .sh, le das permisos de ejecución y lo lanzas cuando quieras. Es como crear una receta: escribes los pasos una vez y los repites cuantas veces necesites, de forma idéntica y sin errores humanos.
La potencia de Bash reside en su capacidad para combinar herramientas pequeñas y especializadas en flujos de trabajo complejos. Esta filosofía, heredada directamente de Unix, se conoce como el principio de composición: cada programa hace una sola cosa bien, y tú los conectas mediante pipes (|) para resolver problemas mayores. Un solo comando de Bash puede encadenar find, grep, sort, awk y sed en una línea que procese gigabytes de logs en pocos segundos.
Ken Thompson (sentado) y Dennis Ritchie frente al PDP-11 en los laboratorios Bell, c. 1973. Su trabajo en Unix sentó los cimientos de la tradición shell que desembocó en Bash. — Foto: Wikimedia Commons, CC BY-SA 2.0.
La historia de Bash está profundamente entrelazada con la de Unix. En 1971, Ken Thompson escribió el primer shell de Unix, un programa minimalista que permitía ejecutar comandos uno a uno. En 1977, Stephen Bourne, trabajando en los laboratorios Bell de AT&T, creó el Bourne Shell (sh), que añadió capacidades de programación: variables, condicionales y bucles. Sin embargo, sh era software propietario de AT&T. Cuando Richard Stallman inició el proyecto GNU en 1983 para construir un sistema operativo completamente libre, necesitaba un shell libre. Brian Fox aceptó el reto y, tras varios años de desarrollo, anunció la primera versión beta de Bash en junio de 1989. El nombre — Bourne Again — es un juego de palabras con «born again» (renacer), señalando que era el renacimiento libre del Bourne Shell original.
Evolución histórica de los shells de Unix y Linux, desde el Thompson Shell original (1971) hasta Fish (2005). Bash ocupa la posición central como el shell más utilizado en el ecosistema Linux.Evolución histórica de los shells de Unix y Linux, desde el Thompson Shell original (1971) hasta Fish (2005). Bash ocupa la posición central como el shell más utilizado en el ecosistema Linux.
Característica
Bash
Python
PowerShell
Plataforma nativa
Linux/macOS
Multiplataforma
Windows
Ideal para
Tareas de sistema, archivos, pipes
Lógica compleja, APIs, datos
Administración Windows
Curva de aprendizaje
Baja para lo básico
Baja-media
Media
Uso en servidores
Ubicuo (96%+ servidores)
Muy extendido
Solo entornos Windows
Procesamiento de texto
Excelente (grep, sed, awk)
Bueno
Bueno
Manipulación de archivos
Nativo y rapidísimo
Requiere módulos (os, shutil)
Bueno (cmdlets)
💡 ¿Cuándo usar Bash vs Python?
La regla de oro es sencilla: usa Bash cuando tu tarea consista principalmente en combinar comandos del sistema — mover archivos, buscar texto, gestionar procesos, programar cron jobs, hacer backups. Usa Python cuando necesites lógica de negocio compleja, estructuras de datos avanzadas (diccionarios, clases), conexiones a APIs REST o procesamiento matemático/estadístico. En la práctica profesional, un buen sysadmin domina ambos y elige la herramienta adecuada para cada tarea.
🚀 Tu primer script
Crear un script de Bash requiere solo tres pasos: crear el archivo, escribir los comandos y darle permisos de ejecución. No necesitas un IDE, un compilador ni librerías externas. Con cualquier editor de texto — desde nano en la terminal hasta VS Code — puedes empezar a programar inmediatamente.
hola.sh — Tu primer script
#!/bin/bash# Mi primer script de Bash# Autor: estudiante de Ciberaula# Fecha: febrero 2026echo"¡Hola, mundo!"echo"Hoy es $(date '+%d de %B de %Y')"echo"Estás conectado como: $(whoami)"echo"En el directorio: $(pwd)"echo"Tu sistema: $(uname -o) $(uname -r)"
terminal — ejecutar el script
# 1. Dar permisos de ejecuciónchmod +x hola.sh
# 2. Ejecutar
./hola.sh
# Salida:# ¡Hola, mundo!# Hoy es 25 de febrero de 2026# Estás conectado como: ana# En el directorio: /home/ana# Tu sistema: GNU/Linux 6.5.0-44-generic
La primera línea del script (#!/bin/bash) se denomina shebang (contracción de sharp-bang: almohadilla + exclamación). Es una directiva que le indica al kernel de Linux qué intérprete debe usarse para ejecutar el archivo. Sin ella, el sistema utilizará el shell por defecto del usuario, que podría no ser Bash — en macOS moderno, por ejemplo, el shell por defecto es Zsh. Por seguridad y portabilidad, incluye siempre el shebang como primera línea de tus scripts.
Una alternativa más portable es usar #!/usr/bin/env bash, que busca el ejecutable de Bash en el PATH del sistema. Esto es útil si Bash no está instalado exactamente en /bin/bash, algo que puede ocurrir en algunos entornos como FreeBSD o instalaciones personalizadas.
Anatomía de un script Bash: los cinco componentes fundamentales — shebang, comentarios, variables, funciones y control de flujo.Anatomía de un script Bash: los cinco componentes fundamentales — shebang, comentarios, variables, funciones y control de flujo.
⚠️ Cuidado con los editores de Windows
Si editas un script en Windows y lo copias a Linux, puede fallar de forma silenciosa por los saltos de línea. Windows usa la secuencia \r\n (retorno de carro + nueva línea), mientras que Linux solo usa \n. El carácter \r invisible puede provocar errores como bad interpreter: No such file or directory incluso cuando el shebang parece correcto. Solución: ejecuta dos2unix script.sh o usa sed -i 's/\r$//' script.sh para limpiar el archivo.
📦 Variables y tipos de datos
En Bash, las variables se crean simplemente asignando un valor — sin declarar tipos, sin palabras reservadas especiales. Internamente, todo en Bash es texto; incluso los números se almacenan como cadenas de caracteres, aunque Bash puede operar con ellos aritméticamente cuando se le indica. Esta simplicidad es a la vez su mayor fortaleza (rapidez para crear scripts) y su mayor trampa (errores sutiles si no se respetan las convenciones).
La regla más importante al asignar variables en Bash es: no dejes espacios alrededor del signo igual. Escribir nombre = "Ana" (con espacios) provocará un error, porque Bash interpretará nombre como un comando y = como su primer argumento. La forma correcta es siempre nombre="Ana", pegado y sin espacios.
variables.sh — Tipos y usos de variables
#!/bin/bash# Variables de texto (strings)nombre="Ana García"distro="Ubuntu 24.04 LTS"# Variables numéricas (enteros)edad=30puerto=8080# Sustitución de comandos: capturar salidafecha_actual="$(date '+%Y-%m-%d')"num_usuarios="$(who | wc -l)"ip_local="$(hostname -I | awk '{print $1}')"# Usar variables (siempre con comillas dobles)echo"Hola, $nombre"echo"Distribución: $distro"echo"Fecha: $fecha_actual"echo"Usuarios conectados: $num_usuarios"echo"IP local: $ip_local"# Aritmética con (( ))a=15b=4echo"Suma: $(( a + b ))"# 19echo"División: $(( a / b ))"# 3 (entera)echo"Módulo: $(( a % b ))"# 3# Variables de entorno (exportadas a procesos hijos)export PROYECTO="mi-servidor"export LOG_LEVEL="debug"
Existen dos formas de expandir variables: $variable y ${variable}. La segunda forma, con llaves, es necesaria cuando la variable va seguida de caracteres que podrían confundir a Bash. Por ejemplo, "${archivo}_backup" funciona correctamente, mientras que "$archivo_backup" buscaría una variable llamada archivo_backup (que probablemente no existe). Como buena práctica, muchos programadores usan siempre las llaves para mayor claridad.
Tipo de variable
Sintaxis
Ejemplo
Ámbito
Local (script)
VAR="valor"
RUTA="/tmp"
Solo el script actual
Exportada
export VAR="valor"
export PATH="..."
Script + procesos hijos
Local (función)
local var="valor"
local resultado=0
Solo la función
Especial (readonly)
readonly VAR="valor"
readonly PI=3
Constante inmutable
Array indexado
ARR=(a b c)
frutas=(manzana pera)
Acceso por índice: ${ARR[0]}
Array asociativo
declare -A M
M[clave]="valor"
Acceso por clave (Bash 4+)
✅ Buena práctica: siempre entrecomilla tus variables
Usa siempre "$variable" con comillas dobles. Sin comillas, si una variable contiene espacios (como un nombre de archivo con espacios), Bash la dividirá en varias palabras causando errores inesperados. La excepción es dentro de [[ ]] y (( )), donde Bash no hace word splitting — pero incluso ahí, las comillas no hacen daño y hacen el código más legible.
🔀 Condicionales: if, elif, else, case
Los condicionales permiten que un script tome decisiones: ejecutar un bloque de código u otro en función de si se cumple una condición. Son esenciales para scripts que deben reaccionar al estado del sistema — por ejemplo, comprobar si un archivo existe antes de procesarlo, si un servicio está activo antes de reiniciarlo, o si hay espacio suficiente en disco antes de iniciar una copia de seguridad.
Bash ofrece dos formas de evaluar condiciones: el comando test (que se abrevia como [ ]) y la construcción moderna [[ ]]. La segunda es recomendable en casi todos los casos porque maneja mejor las cadenas con espacios, soporta expresiones regulares con =~, y permite operadores lógicos como && y || directamente dentro de la condición.
condicionales.sh — Ejemplos completos
#!/bin/bash# Ejemplo 1: Comprobar si un archivo existearchivo="/etc/hosts"if [[ -f "$archivo" ]]; thenecho"✓ El archivo $archivo existe"echo" Tamaño: $(stat --format='%s bytes' "$archivo")"echo" Última modificación: $(stat --format='%y' "$archivo" | cut -d. -f1)"elseecho"✗ El archivo $archivo NO existe"exit1fi# Ejemplo 2: Comprobar espacio en discouso_disco="$(df / --output=pcent | tail -1 | tr -d '% ')"if (( uso_disco >= 90 )); thenecho"🔴 CRÍTICO: disco al ${uso_disco}%"elif (( uso_disco >= 70 )); thenecho"🟡 AVISO: disco al ${uso_disco}%"elseecho"🟢 OK: disco al ${uso_disco}%"fi# Ejemplo 3: case para opciones de menúecho"Elige acción: [i]nstalar [a]ctualizar [d]esinstalar"read -r opcion
case"$opcion"in
i|I|instalar)
echo"Instalando..."
;;
a|A|actualizar)
echo"Actualizando..."
;;
d|D|desinstalar)
echo"Desinstalando..."
;;
*)
echo"Opción no reconocida: $opcion"exit1
;;
esac
Operador
Tipo
Significado
Ejemplo
-f
Archivo
Existe y es fichero regular
[[ -f "/etc/passwd" ]]
-d
Archivo
Existe y es directorio
[[ -d "/var/log" ]]
-r / -w / -x
Archivo
Permisos lectura/escritura/ejecución
[[ -w "$archivo" ]]
-z
Cadena
Cadena vacía (longitud cero)
[[ -z "$var" ]]
-n
Cadena
Cadena no vacía
[[ -n "$var" ]]
== / !=
Cadena
Igual / Distinto
[[ "$a" == "$b" ]]
-eq -ne -lt -le -gt -ge
Número
Comparaciones numéricas
[[ "$x" -gt 10 ]]
🔁 Bucles: for, while, until
Los bucles son la estructura que transforma a Bash de un simple ejecutor de comandos en una herramienta de automatización real. Mientras que un condicional decide qué hacer, un bucle decide cuántas veces hacerlo. Son indispensables para procesar listas de archivos, recorrer líneas de un fichero, reintentar operaciones fallidas o monitorizar recursos del sistema de forma continua.
Bash ofrece tres tipos de bucle: for (itera sobre una lista), while (repite mientras la condición sea verdadera) y until (repite hasta que la condición sea verdadera). En la práctica, for y while cubren el 95% de los casos.
bucles.sh — Patrones profesionales
#!/bin/bash# FOR: recorrer archivos de un directorioecho"=== Archivos .log en /var/log ==="for archivo in /var/log/*.log; doif [[ -f "$archivo" ]]; thentamano="$(du -h "$archivo" | cut -f1)"echo" $archivo → $tamano"fidone# FOR con rango numérico (estilo C)echo"=== Tabla del 7 ==="for (( i=1; i<=10; i++ )); doprintf" 7 × %2d = %2d\n""$i""$(( 7 * i ))"done# WHILE: leer fichero línea a líneaecho"=== Usuarios con shell bash ==="while IFS=: read -r usuario _ _ _ _ _ shell; doif [[ "$shell" == "/bin/bash" ]]; thenecho" $usuario"fidone < /etc/passwd
# WHILE: monitorizar un proceso cada 5 segundosmax_intentos=3intento=0while (( intento < max_intentos )); doifping -c1 -W2 google.com &>/dev/null; thenecho"✓ Conexión OK"breakfi
(( intento++ ))
echo" Intento $intento de $max_intentos fallido..."sleep2doneif (( intento == max_intentos )); thenecho"✗ Sin conexión tras $max_intentos intentos"fi
💡 Truco: procesar la salida de un comando con while
Un patrón muy útil es usar while read combinado con la sustitución de procesos: while IFS= read -r linea; do ... done < <(comando). A diferencia de comando | while read (que abre un subshell donde las variables se pierden), la sustitución de procesos con <() mantiene las variables accesibles tras el bucle. Es un detalle técnico que marca la diferencia entre un script amateur y uno profesional.
🧩 Funciones
Las funciones son bloques de código reutilizables que encapsulan una tarea específica. En scripts de más de 50 líneas, son absolutamente imprescindibles para mantener el código organizado, legible y mantenible. Una función en Bash se declara con nombre() { ... } y se invoca simplemente escribiendo su nombre, como si fuera un comando más del sistema.
A diferencia de la mayoría de lenguajes de programación, las funciones de Bash no declaran parámetros con nombre. Los argumentos se pasan por posición y se acceden dentro de la función con $1, $2, etc. — igual que los argumentos de un script completo. La variable $# contiene el número de argumentos recibidos, y $@ los contiene todos como una lista.
funciones.sh — Funciones profesionales
#!/bin/bash# Función con validación de argumentoslog() {
local nivel="${1:?Falta nivel: info|warn|error}"local mensaje="${2:?Falta mensaje}"local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"case"$nivel"in
info) printf"[%s] \033[32mINFO\033[0m %s\n""$timestamp""$mensaje" ;;
warn) printf"[%s] \033[33mWARN\033[0m %s\n""$timestamp""$mensaje" ;;
error) printf"[%s] \033[31mERROR\033[0m %s\n""$timestamp""$mensaje" >&2 ;;
*) printf"[%s] %s %s\n""$timestamp""$nivel""$mensaje" ;;
esac
}
# Función que retorna un código de salidacomprobar_servicio() {
local servicio="$1"ifsystemctl is-active --quiet "$servicio"2>/dev/null; then
log info "Servicio '$servicio' activo"return0else
log warn "Servicio '$servicio' inactivo"return1fi
}
# Uso
log info "Script iniciado"for srv in nginx mysql ssh; do
comprobar_servicio "$srv"done
log info "Script finalizado"
✅ Buena práctica: usa local para todas las variables dentro de funciones
Sin local, las variables creadas dentro de una función son globales y pueden sobrescribir accidentalmente variables del mismo nombre en el ámbito principal. Esta es una de las fuentes de bugs más comunes en scripts Bash complejos. Declara siempre tus variables de función con local para aislar su ámbito.
📥 Entrada de usuario y argumentos
Un script profesional debe ser flexible: capaz de recibir datos tanto desde la línea de comandos (argumentos posicionales) como de forma interactiva (pidiendo entrada al usuario). Dominar ambas técnicas permite crear herramientas versátiles que se adaptan tanto al uso manual como a la automatización con cron o systemd timers.
entrada.sh — Argumentos y entrada interactiva
#!/bin/bash# Parámetros posicionalesecho"Nombre del script: $0"echo"Primer argumento: ${1:-<no proporcionado>}"echo"Segundo argumento: ${2:-<no proporcionado>}"echo"Total de argumentos: $#"echo"Todos los argumentos: $@"# Validar número mínimo de argumentosif (( $# < 1 )); thenecho"Uso: $0 <directorio> [extensión]" >&2
exit1fi# Lectura interactiva con readread -rp "¿Confirmar la operación? [s/n]: " respuesta
if [[ "$respuesta" =~ ^[sS]$ ]]; thenecho"Procesando..."elseecho"Cancelado por el usuario"exit0fi# Lectura de contraseña (sin eco en pantalla)read -rsp "Introduce tu contraseña: " password
echo# salto de línea tras la entrada ocultaecho"Contraseña recibida (${#password} caracteres)"
🔍 Procesamiento de texto: grep, sed, awk
Si hay una habilidad que distingue a un usuario avanzado de Linux de un principiante, es el dominio de la tríada grep, sed y awk. Estas tres herramientas, todas con décadas de historia en el ecosistema Unix, permiten buscar, filtrar, transformar y analizar texto con una potencia y velocidad que difícilmente igualan los lenguajes de programación modernos cuando se trata de procesar archivos de log, configuraciones o datos tabulares directamente desde la terminal.
grep (Global Regular Expression Print) busca líneas que coincidan con un patrón. sed (Stream Editor) transforma texto sobre la marcha: reemplaza cadenas, elimina líneas, inserta contenido. awk es un lenguaje de procesamiento de campos orientado a columnas, ideal para datos estructurados en columnas separadas por espacios o caracteres delimitadores.
Pipeline de procesamiento de texto Unix: grep filtra, sed transforma y awk extrae columnas. Conectados con pipes, procesan miles de líneas en milisegundos.Pipeline de procesamiento de texto Unix: grep filtra, sed transforma y awk extrae columnas. Conectados con pipes, procesan miles de líneas en milisegundos.
texto.sh — grep, sed, awk en acción
#!/bin/bash# ──── grep: buscar y filtrar ────# Buscar errores en logs (case-insensitive, con número de línea)grep -in "error\|failed\|critical" /var/log/syslog
# Buscar archivos PHP que contengan "mysql_query" (obsoleto)grep -rl "mysql_query" /var/www/ --include="*.php"# Contar cuántas veces aparece cada IP en access.loggrep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log | sort | uniq -c | sort -rn | head10# ──── sed: transformar texto ────# Reemplazar texto en un archivo (in-place con backup)sed -i.bak 's/localhost/192.168.1.100/g' config.ini
# Eliminar líneas vacías y comentarios de un fichero de configuraciónsed'/^$/d; /^#/d' /etc/ssh/sshd_config
# Insertar texto después de una línea específicased'/\[mysqld\]/a max_connections = 500' /etc/mysql/my.cnf
# ──── awk: procesar columnas ────# Mostrar usuarios y sus shellsawk -F: '{printf "%-20s %s\n", $1, $7}' /etc/passwd
# Sumar el tamaño de archivos .logls -l *.log | awk'{total += $5} END {printf "Total: %.2f MB\n", total/1024/1024}'# Analizar access.log: top 5 URLs más visitadasawk'{print $7}' access.log | sort | uniq -c | sort -rn | head5
🐛 Depuración de scripts
Depurar scripts Bash puede ser frustrante si no conoces las herramientas disponibles. A diferencia de Python o Java, donde un error detiene la ejecución con un mensaje claro, Bash por defecto continúa ejecutando tras un error silencioso. Esta permisividad es peligrosa: un script de backup puede fallar en la copia pero seguir ejecutando la rotación, borrando archivos sin tener el respaldo. La solución es activar el modo estricto al inicio de todo script serio.
Modo estricto — primera línea tras el shebang
#!/bin/bashset -euo pipefail
# -e → Detener al primer error (exit code ≠ 0)# -u → Error si se usa una variable no definida# -o pipefail → El pipe falla si falla cualquier comando, no solo el último# Para depuración, añade -x para ver cada comando antes de ejecutarse:# set -euxo pipefail# La -x imprime cada línea con un + antes de ejecutarla, mostrando# las expansiones de variables ya resueltas
La opción -x (xtrace) es tu mejor aliada durante el desarrollo. Muestra cada comando justo antes de ejecutarlo, con todas las variables ya expandidas a sus valores reales. Esto te permite ver exactamente qué está haciendo tu script en cada paso. Puedes activarla para una sección específica con set -x al inicio y set +x al final, sin necesidad de depurar todo el script.
Técnica
Comando
Cuándo usarla
Modo estricto
set -euo pipefail
Siempre, en todos tus scripts
Traza de ejecución
set -x / bash -x script.sh
Cuando necesitas ver qué se ejecuta
Verificar sintaxis
bash -n script.sh
Antes de ejecutar por primera vez
Linter estático
shellcheck script.sh
Siempre, como paso de calidad
Trap para errores
trap 'echo "Error L$LINENO"' ERR
Scripts largos con múltiples fallos posibles
⚠️ Instala ShellCheck — tu mejor aliado
ShellCheck es un analizador estático de scripts Bash que detecta errores comunes, variables sin comillas, usos incorrectos de [ ] vs [[ ]], y decenas de malas prácticas. Puedes usarlo online o instalarlo con sudo apt install shellcheck. Ejecuta shellcheck script.sh antes de cada deploy — encontrarás bugs que ni una revisión manual detectaría.
✏️ Ejercicios resueltos
La programación solo se aprende practicando. Estos dos ejercicios están diseñados para integrar los conceptos vistos: variables, condicionales, bucles, funciones y procesamiento de texto. Intenta resolverlos por tu cuenta antes de consultar la solución.
Ejercicio 1: Renombrador masivo de archivos
Enunciado: Escribe un script que reciba un directorio como argumento y renombre todos los archivos .jpeg a .jpg, mostrando un resumen de cuántos archivos se renombraron.
Enunciado: Crea un script que compruebe el uso de disco de todas las particiones montadas. Si alguna supera el 80%, debe generar una alerta con el formato [ALERTA] /dev/sda1 → 87% (montado en /).
Ver solución del Ejercicio 2
monitor_disco.sh
#!/bin/bashset -euo pipefail
UMBRAL=80alertas=0echo"=== Monitor de disco — $(date '+%d/%m/%Y %H:%M') ==="whileread -r dispositivo tamano usado disponible porcentaje montaje; douso="${porcentaje%\%}"# quitar el símbolo %if (( uso >= UMBRAL )); thenprintf"[ALERTA] %-15s → %3s%% (montado en %s)\n""$dispositivo""$uso""$montaje"
(( alertas++ ))
elseprintf"[ OK ] %-15s → %3s%% (montado en %s)\n""$dispositivo""$uso""$montaje"fidone < <(df --output=source,size,used,avail,pcent,target -x tmpfs -x devtmpfs | tail -n +2)
echo"--- Total alertas: $alertas ---"
🎯 Proyecto integrador: backup automático con rotación
Este proyecto combina todo lo aprendido en un script profesional que podrías desplegar hoy en un servidor de producción. El script comprime un directorio origen en un archivo .tar.gz con fecha, lo almacena en un directorio de destino, mantiene solo las últimas N copias (rotación automática) y genera un log de cada ejecución. Incluye validación de argumentos, manejo de errores con trap y funciones modulares.
backup.sh — Proyecto completo de backup con rotación
#!/bin/bashset -euo pipefail
# ═══════════════════════════════════════════# BACKUP AUTOMÁTICO CON ROTACIÓN# Uso: ./backup.sh /ruta/origen /ruta/destino [max_copias]# ═══════════════════════════════════════════# --- Configuración ---ORIGEN="${1:?Uso: $0 <origen> <destino> [max_copias]}"DESTINO="${2:?Falta directorio de destino}"MAX_COPIAS="${3:-7}"# por defecto, 7 backupsFECHA="$(date '+%Y%m%d_%H%M%S')"NOMBRE_BASE="$(basename "$ORIGEN")"ARCHIVO="${DESTINO}/backup_${NOMBRE_BASE}_${FECHA}.tar.gz"LOG="${DESTINO}/backup.log"# --- Función de logging ---log() {
local mensaje="[$(date '+%Y-%m-%d %H:%M:%S')] $1"echo"$mensaje"echo"$mensaje" >> "$LOG"
}
# --- Limpieza en caso de error ---cleanup() {
if [[ -f "$ARCHIVO" ]] && [[ ! -s "$ARCHIVO" ]]; thenrm -f "$ARCHIVO"
log "ERROR: backup incompleto eliminado"fi
}
trap cleanup ERR
# --- Validaciones ---if [[ ! -d "$ORIGEN" ]]; then
log "ERROR: '$ORIGEN' no existe o no es directorio"exit1fimkdir -p "$DESTINO"# --- Crear backup ---
log "Iniciando backup de '$ORIGEN'..."inicio="$(date +%s)"tar -czf "$ARCHIVO" -C "$(dirname "$ORIGEN")""$NOMBRE_BASE"fin="$(date +%s)"duracion="$(( fin - inicio ))"tamano="$(du -h "$ARCHIVO" | cut -f1)"
log "✓ Backup completado: $ARCHIVO ($tamano, ${duracion}s)"# --- Rotación: eliminar los más antiguos ---num_backups="$(find "$DESTINO" -name "backup_${NOMBRE_BASE}_*.tar.gz" | wc -l)"if (( num_backups > MAX_COPIAS )); theneliminar="$(( num_backups - MAX_COPIAS ))"
log "Rotación: eliminando $eliminar backup(s) antiguos..."find"$DESTINO" -name "backup_${NOMBRE_BASE}_*.tar.gz" -type f \
| sort | head -n "$eliminar" \
| whileread -r viejo; dorm -f "$viejo"
log " Eliminado: $(basename "$viejo")"donefi
log "Backup finalizado. Copias conservadas: $MAX_COPIAS"
💡 Automatiza con cron
Para ejecutar este script cada día a las 3:00 AM, añade una entrada al crontab con crontab -e: 0 3 * * * /home/ana/scripts/backup.sh /var/www /backup 7 2>&1
⚠️ Errores frecuentes y buenas prácticas
Incluso programadores experimentados cometen errores en Bash debido a su sintaxis particular. Estos son los errores que más tiempo consumen en depuración, junto con la solución correcta para cada uno. Aprenderlos te ahorrará incontables horas de frustración.
Error
Código incorrecto
Código correcto
Explicación
Espacios en asignación
nombre = "Ana"
nombre="Ana"
Los espacios hacen que Bash trate nombre como comando
Antes de considerar un script «terminado», verifica estos puntos: (1) tiene shebang #!/bin/bash en la línea 1; (2) usa set -euo pipefail; (3) todas las variables están entrecomilladas; (4) valida los argumentos de entrada; (5) usa funciones para bloques reutilizables; (6) pasa ShellCheck sin advertencias; (7) tiene comentarios en las secciones no obvias; (8) los mensajes de error van a stderr (>&2).
❓ Preguntas frecuentes sobre Bash scripting desde cero: guía completa para automatizar Linux
Las dudas más comunes respondidas de forma clara y directa.
Bash scripting es la escritura de programas (scripts) usando el intérprete de comandos Bash de Linux. Permite automatizar tareas repetitivas, combinar comandos del sistema y crear herramientas personalizadas. Es el lenguaje de automatización más extendido en servidores Linux y una habilidad fundamental para administradores de sistemas y DevOps.
No es necesario tener experiencia previa en programación. Bash tiene una sintaxis relativamente sencilla y, al tratarse de comandos del sistema, puedes ir aprendiendo de forma incremental: primero ejecutas comandos sueltos, luego los combinas en scripts simples, y poco a poco vas añadiendo lógica con variables, condicionales y bucles.
Shell es un término genérico para cualquier intérprete de comandos (sh, bash, zsh, fish, etc.). Bash (Bourne Again SHell) es una implementación concreta de shell y la más extendida en distribuciones Linux. Cuando alguien dice «script de shell» normalmente se refiere a un script de Bash.
Sí, mediante WSL (Windows Subsystem for Linux) puedes ejecutar Bash de forma nativa en Windows 10/11. También puedes usar Git Bash, que incluye una versión de Bash para Windows. Sin embargo, la experiencia completa se obtiene en un sistema Linux nativo.
Bash es ideal para tareas de sistema: mover archivos, ejecutar comandos, procesar texto y automatizar despliegues. Python es mejor para lógica compleja, procesamiento de datos, APIs y aplicaciones. Lo habitual en el mundo profesional es dominar ambos: Bash para tareas rápidas de sistema y Python para scripts más elaborados.
Hay dos formas principales: (1) darle permisos de ejecución con chmod +x script.sh y ejecutarlo con ./script.sh, o (2) invocarlo directamente con bash script.sh. La primera es la forma estándar en entornos de producción. Siempre debe empezar con la línea #!/bin/bash (shebang) para indicar el intérprete.
Las tres herramientas fundamentales son grep (buscar texto), sed (sustituir y transformar texto) y awk (procesar texto por columnas). Juntas forman la «santísima trinidad» del procesamiento de texto en Linux y se combinan constantemente con pipes (|) en scripts Bash.
★★★★★
Valora este artículo
¿Útil?
💬 Foro de discusión
¿Tienes dudas sobre Bash scripting desde cero: guía completa para automatizar Linux? Comparte tu pregunta con la comunidad.
¿Tienes cuenta?o comenta como invitado ↓
Iniciar sesión
🔑 Recuperar contraseña
Introduce el email con el que te registraste. Te enviaremos un enlace para crear una nueva contraseña.
Crear cuenta
Solo necesitas nombre, email y contraseña. Sin verificación por email.
Todavía no hay mensajes. ¡Sé el primero en participar!
🚀 ¿Quieres dominar Linux profesionalmente?
Cursos bonificados por FUNDAE para empresas — formación 100% subvencionada
Usamos cookies propias para mejorar tu experiencia de navegación y analizar
el uso del sitio. No compartimos datos con terceros ni usamos cookies de
publicidad. Puedes aceptar todas, aceptar solo las necesarias o configurar
tus preferencias.
Política de privacidad
Imprescindibles para el funcionamiento del sitio: preferencias de interfaz,
gestión de sesiones y este mismo aviso de cookies. No recogen datos
identificativos.
Nos permiten entender cómo navegas por el contenido para mejorar la
experiencia de aprendizaje. Utilizan identificadores anónimos (UUID) sin
vinculación a datos personales. Retención máxima: 6 meses.
¿Cómo valorarías tu experiencia aprendiendo en esta sección?