Captura de Señales en Bash con el Comando trap

En scripts de Shell extensos y complejos, es esencial considerar eventos como la desconexión del usuario o apagones del sistema. Estos eventos envían señales que deben ser capturadas y manejadas para finalizar el programa de forma controlada y segura.

El comando interno de Bash trap permite capturar señales específicas en un script y ejecutar acciones predefinidas en respuesta a ellas.

Sintaxis: trap 'comando' señal [señal ...]

Aquí, comando puede ser un script o función, y señal se especifica por nombre o valor. Ejecutar trap sin argumentos muestra las trampas configuradas actualmente.

1. Configuración de una trampa para errores (ERR)

La señal ERR se activa cuando un comando finaliza con un estado distinto de cero, a menos que provenga de una estructura condicional como if o bucles como while.

# Generar un nombre de archivo temporal único
TEMP_FILE=$(mktemp -u /tmp/error_log.$$..tmp)

# Establecer una trampa para señales ERR
trap 'echo "Se ha producido un error durante la ejecución"' ERR

# Verificar la configuración
trap

# Intentar eliminar un archivo inexistente para activar ERR
rm "$TEMP_FILE"

2. Uso de la trampa DEBUG para depuración

La señal DEBUG se dispara después de cada comando en el script, lo cual es útil para monitorear variables o ejecutar seguimiento.

#!/bin/bash
# Script de ejemplo con trampa DEBUG

# Declarar una variable con atributo de rastreo
declare -t VAR_MONITOR=valor_inicial

# Configurar trampa para depuración
trap 'echo "La variable VAR_MONITOR está siendo evaluada"' DEBUG

# Cambiar el valor de la variable, activando la trampa
VAR_MONITOR=nuevo_valor

# Imprimir el valor, activando la trampa nuevamente
echo "El valor actual de VAR_MONITOR es: $VAR_MONITOR"

3. Captura de señales de terminación (Exit)

La señal 0 o EXIT se ejecuta cuando el script finaliza, independientemente del código de salida.

#!/bin/bash
# Ejemplo de captura de EXIT

trap 'echo "El script ha finalizado con código de salida $?"' 0

echo "Ejecutando tareas principales..."

# Terminar con código de salida 0
exit 0

4. Manejo de SIGINT y SIGTERM

Estas señales corresponden a interrupciones de teclado (Ctrl+C) y solicitudes de terminación, respectivamente. Se pueden capturar para evitar finalizaciones abruptas.

#!/bin/bash
# Script que ignora SIGINT y SIGTERM

trap 'echo "Señal SIGINT recibida, ignorando..."' SIGINT
trap 'echo "Señal SIGTERM recibida, continuando ejecución..."' SIGTERM

# Bucle para simular trabajo en segundo plano
for iter in {1..5}
do
    echo "Iteración $iter de 5"
    sleep 4
done

Durante la ejecución, usar Ctrl+C mostrará el mensaje de SIGINT, y intentar finalizar con kill mostrará el de SIGTERM.

5. Ignorar señales específicas

Para evitar que ciertas señales interrumpan el script, se puede usar una cadena vacía en el comando de trap.

trap '' SIGHUP SIGINT SIGQUIT

Esto hace que el script ignore dichas señales hasta que se redefina la trampa.

Uso avanzado: trampas con funciones y variables internas

Las variables de Bash LINENO y BASH_COMMAND proporcionen información sobre la línea y comando en ejecución cuando se captura una señal.

#!/bin/bash
# Ejemplo con función de limpieza

# Función para manejar señales
manejar_senal() {
    echo "Error en línea $1, comando: $2"
    logger -p notice "Script $(basename $0) terminado: línea $1, comando $2"
    exit 1
}

trap 'manejar_senal $LINENO $BASH_COMMAND; exit' SIGHUP SIGINT SIGQUIT

# Bucle infinito
contador=0
while :
do
    contador=$((contador + 1))
    echo "Contador: $contador"
    sleep 2
done

Reconfiguración y eliminación de trampas

Las trampas se pueden desactivar temporalmente o eliminar permanentemente con trap - señal. Esto es útil para secciones del script donde ciertas señales deben manejarse de forma diferente.

#!/bin/bash
# Ejemplo de reconfiguración de trampas

# Ignorar SIGQUIT y SIGINT inicialmente
trap '' SIGQUIT SIGINT

echo "No se puede interrumpir con Ctrl+C o Ctrl+\\."
sleep 8

# Redefinir trampas para capturar señales
trap 'echo "Interrupción detectada, finalizando..."; exit' SIGQUIT SIGINT

echo "Ahora se puede interrumpir con las teclas mencionadas."
sleep 8

Para limpiar recursos, como archivos temporales, se pueden usar trampas que eliminen dichos archivos al recibir señales, y luego remover las trampas cuando ya no sean necesarias.

#!/bin/bash
# Script con limpieza de archivos temporales

limpiar() {
    if [[ -e $archivo_temp ]]; then
        echo "Líneas escritas: $(wc -l < $archivo_temp)"
        mv "$archivo_temp" "$archivo_temp.bak"
    fi
    exit
}

trap limpiar INT TERM

archivo_temp=$(mktemp /tmp/datos.$$..tmp)
cat > "$archivo_temp"
# Procesamiento adicional...

# Si se completa sin interrupciones, remover la trampa
trap - INT TERM
rm "$archivo_temp"

Etiquetas: bash trap Señales script shell linux

Publicado el 6-30 19:32