¿Qué son las Librerías de Funciones?
Las librerías de funciones son archivos que contienen funciones reutilizables que pueden ser importadas y utilizadas en múltiples scripts. Esto permite crear un ecosistema de código modular, mantenible y eficiente.
En Bash, usamos el comando source (o su alias .) para cargar funciones y variables desde otros archivos al script actual.
Estructura Típica de Librerías
El Comando Source
El comando source carga y ejecuta comandos desde otro archivo en el contexto del shell actual. Esto significa que todas las funciones y variables definidas en el archivo fuente se vuelven disponibles en el script actual.
Comando source
# Sintaxis completa
source /ruta/al/archivo.sh
# Usando ruta relativa
source ./lib/utils.sh
# Con validación
source "$HOME/lib/config.sh"
Comando punto (.)
# Alias del comando source
. /ruta/al/archivo.sh
# Más compacto y común
. ./lib/utils.sh
# Funcionalmente idéntico a source
. "$HOME/lib/config.sh"
Diferencia importante
Usar source o . ejecuta el archivo en el shell actual, mientras que ejecutarlo directamente (./archivo.sh) lo ejecuta en un subshell separado.
Creando Tu Primera Librería
Vamos a crear una librería de utilidades comunes paso a paso:
1. Librería de Utilidades Generales
#!/bin/bash
# =============================================================================
# LIBRERÍA DE UTILIDADES GENERALES
# Archivo: lib/utils.sh
# Descripción: Funciones comunes para scripts Bash
# =============================================================================
# Prevenir carga múltiple
if [[ "${UTILS_LIB_LOADED:-}" == "true" ]]; then
return 0
fi
readonly UTILS_LIB_LOADED=true
# =============================================================================
# CONSTANTES
# =============================================================================
readonly UTILS_VERSION="1.0.0"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# =============================================================================
# FUNCIONES DE VALIDACIÓN
# =============================================================================
# Verificar si un comando está disponible
comando_disponible() {
local comando="$1"
command -v "$comando" >/dev/null 2>&1
}
# Verificar si es un número
es_numero() {
local valor="$1"
[[ "$valor" =~ ^-?[0-9]+([.][0-9]+)?$ ]]
}
# Verificar si es un entero
es_entero() {
local valor="$1"
[[ "$valor" =~ ^-?[0-9]+$ ]]
}
# Verificar si es un email válido
es_email() {
local email="$1"
[[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]
}
# Verificar si es una URL válida
es_url() {
local url="$1"
[[ "$url" =~ ^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(/.*)?$ ]]
}
# =============================================================================
# FUNCIONES DE ARCHIVOS Y DIRECTORIOS
# =============================================================================
# Crear directorio con permisos específicos
crear_directorio() {
local directorio="$1"
local permisos="${2:-755}"
if [ ! -d "$directorio" ]; then
mkdir -p "$directorio"
chmod "$permisos" "$directorio"
echo "Directorio creado: $directorio"
else
echo "Directorio ya existe: $directorio"
fi
}
# Crear backup de archivo con timestamp
crear_backup() {
local archivo="$1"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup="${archivo}.backup_${timestamp}"
if [ -f "$archivo" ]; then
cp "$archivo" "$backup"
echo "Backup creado: $backup"
return 0
else
echo "Error: Archivo no encontrado: $archivo"
return 1
fi
}
# Obtener tamaño de archivo en formato legible
tamaño_archivo() {
local archivo="$1"
if [ -f "$archivo" ]; then
if comando_disponible "du"; then
du -h "$archivo" | cut -f1
else
ls -lh "$archivo" | awk '{print $5}'
fi
else
echo "N/A"
fi
}
# =============================================================================
# FUNCIONES DE TEXTO Y CADENAS
# =============================================================================
# Convertir a mayúsculas
a_mayusculas() {
local texto="$1"
echo "$texto" | tr '[:lower:]' '[:upper:]'
}
# Convertir a minúsculas
a_minusculas() {
local texto="$1"
echo "$texto" | tr '[:upper:]' '[:lower:]'
}
# Limpiar espacios en blanco
limpiar_espacios() {
local texto="$1"
echo "$texto" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'
}
# Generar cadena aleatoria
generar_cadena_aleatoria() {
local longitud="${1:-8}"
local caracteres="${2:-A-Za-z0-9}"
if comando_disponible "head" && comando_disponible "tr"; then
head /dev/urandom | tr -dc "$caracteres" | head -c "$longitud"
echo
else
# Método alternativo usando $RANDOM
local cadena=""
local chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for ((i=0; i&2; }
# =============================================================================
# FUNCIÓN DE INFORMACIÓN DE LA LIBRERÍA
# =============================================================================
utils_info() {
echo "=== Librería de Utilidades ==="
echo "Versión: $UTILS_VERSION"
echo "Ubicación: $SCRIPT_DIR"
echo "Funciones disponibles:"
echo " Validación: comando_disponible, es_numero, es_entero, es_email, es_url"
echo " Archivos: crear_directorio, crear_backup, tamaño_archivo"
echo " Texto: a_mayusculas, a_minusculas, limpiar_espacios, generar_cadena_aleatoria"
echo " Fecha: timestamp, fecha_iso, fecha_legible, diferencia_tiempo"
echo " Sistema: info_sistema, es_root, uso_memoria"
echo " Logging: log_info, log_warning, log_error"
}
# Mostrar mensaje de carga
log_info "Librería de utilidades cargada (v$UTILS_VERSION)"
2. Script que Usa la Librería
#!/bin/bash
# Script de ejemplo que usa la librería de utilidades
# Cargar la librería de utilidades
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/utils.sh"
# Función principal
main() {
log_info "Iniciando script de ejemplo"
# Mostrar información de la librería
utils_info
echo ""
log_info "=== Probando funciones de validación ==="
# Probar validaciones
local test_email="[email protected]"
local test_numero="123.45"
local test_url="https://www.example.com"
if es_email "$test_email"; then
log_info "✓ Email válido: $test_email"
else
log_error "✗ Email inválido: $test_email"
fi
if es_numero "$test_numero"; then
log_info "✓ Número válido: $test_numero"
else
log_error "✗ Número inválido: $test_numero"
fi
if es_url "$test_url"; then
log_info "✓ URL válida: $test_url"
else
log_error "✗ URL inválida: $test_url"
fi
echo ""
log_info "=== Probando funciones de texto ==="
local texto_original=" Hola Mundo Bash "
log_info "Texto original: '$texto_original'"
log_info "Mayúsculas: '$(a_mayusculas "$texto_original")'"
log_info "Minúsculas: '$(a_minusculas "$texto_original")'"
log_info "Sin espacios: '$(limpiar_espacios "$texto_original")'"
echo ""
log_info "=== Probando generación de cadenas ==="
log_info "Cadena aleatoria (8 chars): $(generar_cadena_aleatoria)"
log_info "Cadena aleatoria (16 chars): $(generar_cadena_aleatoria 16)"
log_info "Solo números (10 chars): $(generar_cadena_aleatoria 10 "0-9")"
echo ""
log_info "=== Probando funciones de fecha ==="
log_info "Timestamp: $(timestamp)"
log_info "Fecha ISO: $(fecha_iso)"
log_info "Fecha legible: $(fecha_legible)"
echo ""
log_info "=== Probando funciones de sistema ==="
info_sistema
if es_root; then
log_warning "Ejecutándose como root"
else
log_info "Ejecutándose como usuario normal"
fi
log_info "Uso de memoria: $(uso_memoria)"
echo ""
log_info "=== Probando funciones de archivos ==="
# Crear directorio de prueba
local test_dir="/tmp/test_library_$$"
crear_directorio "$test_dir"
# Crear archivo de prueba
local test_file="$test_dir/test_file.txt"
echo "Contenido de prueba $(fecha_legible)" > "$test_file"
log_info "Archivo creado: $test_file"
log_info "Tamaño del archivo: $(tamaño_archivo "$test_file")"
# Crear backup
crear_backup "$test_file"
# Listar archivos en el directorio de prueba
log_info "Archivos en $test_dir:"
ls -la "$test_dir"
# Limpiar
rm -rf "$test_dir"
log_info "Directorio de prueba limpiado"
log_info "Script completado exitosamente"
}
# Ejecutar función principal
main "$@"
$ ./ejemplo_uso.sh
[2024-01-15 10:30:15] [INFO] Librería de utilidades cargada (v1.0.0)
[2024-01-15 10:30:15] [INFO] Iniciando script de ejemplo
=== Librería de Utilidades ===
Versión: 1.0.0
Ubicación: /home/usuario/proyecto/lib
Funciones disponibles:
Validación: comando_disponible, es_numero, es_entero, es_email, es_url
Archivos: crear_directorio, crear_backup, tamaño_archivo
Texto: a_mayusculas, a_minusculas, limpiar_espacios, generar_cadena_aleatoria
Fecha: timestamp, fecha_iso, fecha_legible, diferencia_tiempo
Sistema: info_sistema, es_root, uso_memoria
Logging: log_info, log_warning, log_error
[2024-01-15 10:30:15] [INFO] === Probando funciones de validación ===
[2024-01-15 10:30:15] [INFO] ✓ Email válido: [email protected]
[2024-01-15 10:30:15] [INFO] ✓ Número válido: 123.45
[2024-01-15 10:30:15] [INFO] ✓ URL válida: https://www.example.com
Librerías Especializadas
Ahora creemos librerías más especializadas para diferentes propósitos:
Librería de Base de Datos
#!/bin/bash
# =============================================================================
# LIBRERÍA DE BASE DE DATOS
# Funciones para interactuar con bases de datos
# =============================================================================
if [[ "${DATABASE_LIB_LOADED:-}" == "true" ]]; then
return 0
fi
readonly DATABASE_LIB_LOADED=true
# Configuración por defecto
DB_HOST="${DB_HOST:-localhost}"
DB_PORT="${DB_PORT:-5432}"
DB_NAME="${DB_NAME:-postgres}"
DB_USER="${DB_USER:-postgres}"
DB_TIMEOUT="${DB_TIMEOUT:-10}"
# Verificar conexión a PostgreSQL
db_test_connection() {
local host="${1:-$DB_HOST}"
local port="${2:-$DB_PORT}"
local user="${3:-$DB_USER}"
local database="${4:-$DB_NAME}"
log_info "Probando conexión a $host:$port/$database como $user"
if command -v psql >/dev/null 2>&1; then
if timeout "$DB_TIMEOUT" psql -h "$host" -p "$port" -U "$user" -d "$database" -c "SELECT 1;" >/dev/null 2>&1; then
log_info "✓ Conexión exitosa"
return 0
else
log_error "✗ Error de conexión"
return 1
fi
else
log_error "psql no está disponible"
return 1
fi
}
# Ejecutar query y devolver resultado
db_query() {
local query="$1"
local host="${2:-$DB_HOST}"
local port="${3:-$DB_PORT}"
local user="${4:-$DB_USER}"
local database="${5:-$DB_NAME}"
if command -v psql >/dev/null 2>&1; then
psql -h "$host" -p "$port" -U "$user" -d "$database" -t -c "$query" 2>/dev/null
else
log_error "psql no está disponible"
return 1
fi
}
# Crear backup de base de datos
db_backup() {
local database="${1:-$DB_NAME}"
local backup_dir="${2:-/tmp/backups}"
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_file="$backup_dir/${database}_backup_${timestamp}.sql"
crear_directorio "$backup_dir"
log_info "Creando backup de $database en $backup_file"
if command -v pg_dump >/dev/null 2>&1; then
if pg_dump -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" "$database" > "$backup_file"; then
log_info "✓ Backup creado: $backup_file"
echo "$backup_file"
return 0
else
log_error "✗ Error creando backup"
return 1
fi
else
log_error "pg_dump no está disponible"
return 1
fi
}
log_info "Librería de base de datos cargada"
Librería de Configuración
#!/bin/bash
# =============================================================================
# LIBRERÍA DE CONFIGURACIÓN
# Funciones para manejo de archivos de configuración
# =============================================================================
if [[ "${CONFIG_LIB_LOADED:-}" == "true" ]]; then
return 0
fi
readonly CONFIG_LIB_LOADED=true
# Array asociativo para almacenar configuración
declare -A CONFIG
# Cargar configuración desde archivo
config_load() {
local config_file="$1"
local prefijo="${2:-}"
if [ ! -f "$config_file" ]; then
log_error "Archivo de configuración no encontrado: $config_file"
return 1
fi
log_info "Cargando configuración desde: $config_file"
local contador=0
while IFS= read -r linea || [ -n "$linea" ]; do
# Omitir líneas vacías y comentarios
if [[ "$linea" =~ ^[[:space:]]*$ ]] || [[ "$linea" =~ ^[[:space:]]*# ]]; then
continue
fi
# Procesar líneas clave=valor
if [[ "$linea" =~ ^[[:space:]]*([^=]+)=[[:space:]]*(.*)$ ]]; then
local clave="${BASH_REMATCH[1]}"
local valor="${BASH_REMATCH[2]}"
# Limpiar espacios
clave=$(echo "$clave" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
valor=$(echo "$valor" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# Añadir prefijo si se especifica
if [ -n "$prefijo" ]; then
clave="${prefijo}_${clave}"
fi
CONFIG["$clave"]="$valor"
((contador++))
fi
done < "$config_file"
log_info "✓ $contador configuraciones cargadas"
return 0
}
# Obtener valor de configuración
config_get() {
local clave="$1"
local valor_por_defecto="$2"
if [[ -n "${CONFIG[$clave]:-}" ]]; then
echo "${CONFIG[$clave]}"
else
echo "$valor_por_defecto"
fi
}
# Establecer valor de configuración
config_set() {
local clave="$1"
local valor="$2"
CONFIG["$clave"]="$valor"
}
# Verificar si una clave existe
config_exists() {
local clave="$1"
[[ -n "${CONFIG[$clave]:-}" ]]
}
# Mostrar toda la configuración
config_show() {
local filtro="${1:-}"
echo "=== Configuración Cargada ==="
for clave in "${!CONFIG[@]}"; do
if [ -z "$filtro" ] || [[ "$clave" == *"$filtro"* ]]; then
echo "$clave = ${CONFIG[$clave]}"
fi
done | sort
}
# Guardar configuración a archivo
config_save() {
local config_file="$1"
local filtro="${2:-}"
log_info "Guardando configuración en: $config_file"
{
echo "# Configuración generada el $(fecha_legible)"
echo ""
for clave in "${!CONFIG[@]}"; do
if [ -z "$filtro" ] || [[ "$clave" == *"$filtro"* ]]; then
echo "$clave=${CONFIG[$clave]}"
fi
done | sort
} > "$config_file"
log_info "✓ Configuración guardada"
}
log_info "Librería de configuración cargada"
Mejores Prácticas para Librerías
Prevenir Carga Múltiple
Usa guardas para evitar cargar la misma librería múltiples veces.
if [[ "${MI_LIB_LOADED:-}" == "true" ]]; then
return 0
fi
readonly MI_LIB_LOADED=true
Usar Prefijos
Añade prefijos a las funciones para evitar conflictos de nombres.
# Bueno
db_connect()
log_info()
config_get()
# Evitar
connect() # Muy genérico
info() # Puede causar conflictos
Documentar Funciones
Incluye documentación clara y ejemplos de uso.
# Función para validar email
# Uso: es_email "[email protected]"
# Retorna: 0 si es válido, 1 si no lo es
es_email() {
local email="$1"
[[ "$email" =~ ^[a-zA-Z0-9._%+-]+@ ]]
}
Validar Dependencias
Verifica que los comandos necesarios estén disponibles.
if ! command -v jq >/dev/null 2>&1; then
log_error "jq es requerido para esta función"
return 1
fi
Manejo de Errores
Implementa manejo robusto de errores y códigos de retorno.
mi_funcion() {
local archivo="$1"
if [ ! -f "$archivo" ]; then
log_error "Archivo no encontrado: $archivo"
return 1
fi
# Procesamiento...
return 0
}
Versionado
Mantén versiones de tus librerías para compatibilidad.
readonly UTILS_VERSION="2.1.0"
utils_version() {
echo "$UTILS_VERSION"
}
utils_require_version() {
local required="$1"
# Lógica de comparación de versiones
}
Proyecto Completo: Sistema de Gestión
Vamos a crear un ejemplo completo que integra múltiples librerías:
#!/bin/bash
# =============================================================================
# SISTEMA DE GESTIÓN COMPLETO
# Ejemplo de integración de múltiples librerías
# =============================================================================
set -euo pipefail # Modo estricto
# =============================================================================
# CONFIGURACIÓN Y CARGA DE LIBRERÍAS
# =============================================================================
# Determinar directorio del script
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly LIB_DIR="$SCRIPT_DIR/lib"
# Función para cargar librerías de forma segura
cargar_libreria() {
local libreria="$1"
local archivo_lib="$LIB_DIR/$libreria"
if [ -f "$archivo_lib" ]; then
source "$archivo_lib"
echo "✓ Librería cargada: $libreria"
else
echo "✗ Error: No se pudo cargar $libreria"
exit 1
fi
}
# Cargar todas las librerías necesarias
echo "=== Cargando librerías ==="
cargar_libreria "utils.sh"
cargar_libreria "config.sh"
cargar_libreria "database.sh"
# =============================================================================
# CONFIGURACIÓN DEL SISTEMA
# =============================================================================
readonly APP_NAME="Sistema de Gestión"
readonly APP_VERSION="1.0.0"
readonly CONFIG_FILE="$SCRIPT_DIR/config/app.conf"
# =============================================================================
# FUNCIONES PRINCIPALES
# =============================================================================
# Inicializar sistema
inicializar_sistema() {
log_info "Inicializando $APP_NAME v$APP_VERSION"
# Crear directorios necesarios
crear_directorio "$SCRIPT_DIR/logs" 700
crear_directorio "$SCRIPT_DIR/config" 755
crear_directorio "$SCRIPT_DIR/backups" 750
# Crear archivo de configuración por defecto si no existe
if [ ! -f "$CONFIG_FILE" ]; then
log_info "Creando archivo de configuración por defecto"
cat > "$CONFIG_FILE" << 'EOF'
# Configuración del Sistema de Gestión
APP_DEBUG=false
LOG_LEVEL=INFO
DB_HOST=localhost
DB_PORT=5432
DB_NAME=sistema
DB_USER=admin
BACKUP_RETENTION_DAYS=7
MAX_LOG_SIZE_MB=100
EOF
fi
# Cargar configuración
if config_load "$CONFIG_FILE"; then
log_info "Configuración cargada desde $CONFIG_FILE"
else
log_error "Error cargando configuración"
return 1
fi
}
# Verificar estado del sistema
verificar_sistema() {
log_info "=== Verificación del Sistema ==="
local errores=0
# Verificar configuración crítica
if ! config_exists "DB_HOST"; then
log_error "Configuración DB_HOST no encontrada"
((errores++))
fi
# Verificar conectividad de base de datos
local db_host=$(config_get "DB_HOST" "localhost")
local db_port=$(config_get "DB_PORT" "5432")
local db_user=$(config_get "DB_USER" "admin")
local db_name=$(config_get "DB_NAME" "sistema")
log_info "Verificando conexión a base de datos..."
if db_test_connection "$db_host" "$db_port" "$db_user" "$db_name"; then
log_info "✓ Conexión a base de datos OK"
else
log_warning "⚠️ No se pudo conectar a la base de datos"
((errores++))
fi
# Verificar espacio en disco
local uso_disco=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$uso_disco" -gt 90 ]; then
log_warning "⚠️ Espacio en disco bajo: ${uso_disco}%"
else
log_info "✓ Espacio en disco OK: ${uso_disco}%"
fi
# Verificar memoria
log_info "Uso de memoria: $(uso_memoria)"
return $errores
}
# Realizar backup del sistema
realizar_backup() {
log_info "=== Iniciando Backup del Sistema ==="
local backup_dir="$SCRIPT_DIR/backups/$(fecha_iso)"
crear_directorio "$backup_dir"
local backup_exitoso=true
# Backup de configuración
log_info "Respaldando configuración..."
if cp -r "$SCRIPT_DIR/config" "$backup_dir/"; then
log_info "✓ Configuración respaldada"
else
log_error "✗ Error respaldando configuración"
backup_exitoso=false
fi
# Backup de base de datos
local db_name=$(config_get "DB_NAME" "sistema")
if [ -n "$db_name" ]; then
log_info "Respaldando base de datos: $db_name"
if db_backup "$db_name" "$backup_dir"; then
log_info "✓ Base de datos respaldada"
else
log_warning "⚠️ Error respaldando base de datos"
fi
fi
# Comprimir backup
local backup_tar="$SCRIPT_DIR/backups/backup_$(timestamp).tar.gz"
log_info "Comprimiendo backup en: $backup_tar"
if tar -czf "$backup_tar" -C "$SCRIPT_DIR/backups" "$(basename "$backup_dir")"; then
log_info "✓ Backup comprimido exitosamente"
rm -rf "$backup_dir"
else
log_error "✗ Error comprimiendo backup"
backup_exitoso=false
fi
if [ "$backup_exitoso" = true ]; then
log_info "✓ Backup completado: $backup_tar"
return 0
else
log_error "✗ Backup completado con errores"
return 1
fi
}
# Limpiar archivos antiguos
limpiar_sistema() {
log_info "=== Limpieza del Sistema ==="
local retention_days=$(config_get "BACKUP_RETENTION_DAYS" "7")
local backups_dir="$SCRIPT_DIR/backups"
# Limpiar backups antiguos
log_info "Limpiando backups más antiguos de $retention_days días..."
local archivos_eliminados=0
if [ -d "$backups_dir" ]; then
while IFS= read -r -d '' archivo; do
log_info "Eliminando backup antiguo: $(basename "$archivo")"
rm -f "$archivo"
((archivos_eliminados++))
done < <(find "$backups_dir" -name "backup_*.tar.gz" -mtime +$retention_days -print0)
fi
log_info "✓ $archivos_eliminados backups antiguos eliminados"
# Limpiar logs grandes
local max_log_size=$(config_get "MAX_LOG_SIZE_MB" "100")
log_info "Verificando tamaño de logs (máximo: ${max_log_size}MB)..."
# Aquí podrías añadir lógica para rotar logs si superan el tamaño
log_info "✓ Limpieza completada"
}
# Mostrar estado del sistema
mostrar_estado() {
echo ""
echo "=== ESTADO DEL SISTEMA ==="
echo "Aplicación: $APP_NAME"
echo "Versión: $APP_VERSION"
echo "Fecha: $(fecha_legible)"
echo ""
info_sistema
echo ""
echo "=== CONFIGURACIÓN ACTIVA ==="
config_show
echo ""
echo "=== RECURSOS DEL SISTEMA ==="
echo "Memoria: $(uso_memoria)"
echo "Espacio en disco: $(df -h / | tail -1 | awk '{print $4}') disponible"
if es_root; then
echo "Privilegios: Administrador"
else
echo "Privilegios: Usuario normal"
fi
}
# =============================================================================
# FUNCIÓN PRINCIPAL Y MENÚ
# =============================================================================
mostrar_menu() {
echo ""
echo "=== $APP_NAME ==="
echo "1. Verificar sistema"
echo "2. Realizar backup"
echo "3. Limpiar sistema"
echo "4. Mostrar estado"
echo "5. Mostrar configuración"
echo "6. Salir"
echo ""
}
procesar_opcion() {
local opcion="$1"
case "$opcion" in
1)
verificar_sistema
;;
2)
realizar_backup
;;
3)
limpiar_sistema
;;
4)
mostrar_estado
;;
5)
config_show
;;
6)
log_info "Saliendo del sistema..."
return 1
;;
*)
log_error "Opción inválida: $opcion"
;;
esac
return 0
}
# Función principal
main() {
# Inicializar sistema
if ! inicializar_sistema; then
log_error "Error en la inicialización del sistema"
exit 1
fi
# Si se pasan argumentos, ejecutar en modo no interactivo
if [ $# -gt 0 ]; then
case "$1" in
"check"|"verificar")
verificar_sistema
;;
"backup")
realizar_backup
;;
"clean"|"limpiar")
limpiar_sistema
;;
"status"|"estado")
mostrar_estado
;;
*)
echo "Uso: $0 [check|backup|clean|status]"
exit 1
;;
esac
exit $?
fi
# Modo interactivo
while true; do
mostrar_menu
read -p "Selecciona una opción: " opcion
if ! procesar_opcion "$opcion"; then
break
fi
echo ""
read -p "Presiona Enter para continuar..."
clear
done
log_info "Sistema terminado"
}
# Manejo de señales
trap 'log_warning "Interrupción recibida, terminando..."; exit 130' INT TERM
# Ejecutar función principal
main "$@"
Características del Sistema Completo
- Modular: Usa múltiples librerías especializadas
- Configurable: Sistema de configuración flexible
- Robusto: Manejo de errores y validaciones
- Interactivo: Menú y modo línea de comandos
- Completo: Backup, limpieza, monitoreo
Ejercicio Práctico
Ejercicio: Crear Tu Propia Librería
Crea una librería de red con las siguientes funciones:
#!/bin/bash
# =============================================================================
# LIBRERÍA DE RED - EJERCICIO
# Completa las siguientes funciones
# =============================================================================
# Prevenir carga múltiple
if [[ "${NETWORK_LIB_LOADED:-}" == "true" ]]; then
return 0
fi
readonly NETWORK_LIB_LOADED=true
# Función para hacer ping a un host
# Uso: ping_host "google.com" [intentos]
ping_host() {
local host="$1"
local intentos="${2:-3}"
# TODO: Implementar ping con número de intentos especificado
# Devolver 0 si hay respuesta, 1 si no la hay
}
# Función para verificar si un puerto está abierto
# Uso: puerto_abierto "localhost" "80"
puerto_abierto() {
local host="$1"
local puerto="$2"
# TODO: Usar nc (netcat) o timeout con bash para verificar puerto
# Devolver 0 si está abierto, 1 si está cerrado
}
# Función para obtener IP pública
# Uso: ip_publica
ip_publica() {
# TODO: Usar curl para obtener IP desde un servicio como ipinfo.io
# Manejar errores si no hay internet
}
# Función para descargar archivo con reintentos
# Uso: descargar_archivo "url" "destino" [reintentos]
descargar_archivo() {
local url="$1"
local destino="$2"
local reintentos="${3:-3}"
# TODO: Implementar descarga con curl/wget y reintentos
# Mostrar progreso y manejar errores
}
# Función para verificar conectividad a internet
# Uso: hay_internet
hay_internet() {
# TODO: Verificar conectividad haciendo ping a DNS públicos
# o intentando resolver un dominio conocido
}
log_info "Librería de red cargada - ¡Completa las funciones!"
Tareas a Completar
- Implementa cada función siguiendo las especificaciones
- Añade manejo de errores apropiado
- Usa las funciones de logging de la librería utils
- Crea un script de prueba que use todas las funciones
- Documenta cada función con comentarios