senales-y-procesos
Señales y procesos
Section titled “Señales y procesos”Control del ciclo de vida de un script y de los procesos: captura de Ctrl+C con
trap, señales, ejecución en segundo plano y en paralelo.
Control de Ctrl+C con trap
Section titled “Control de Ctrl+C con trap”Por defecto, Ctrl+C envía la señal SIGINT y mata el script en el punto en que esté, dejando la terminal en el estado que tuviera (cursor oculto, ficheros temporales sin borrar…). trap intercepta la señal y ejecuta una función de limpieza.
Sintaxis
Section titled “Sintaxis”trap nombre_funcion SEÑALtrap 'comando1; comando2' SEÑALEjemplo básico
Section titled “Ejemplo básico”#!/bin/bash
function ctrl_c(){ echo -e "\n\n[!] Saliendo...\n" tput cnorm # restaura el cursor exit 1}
trap ctrl_c INT
tput civis # oculta el cursorwhile true; do sleep 1donePuntos clave
Section titled “Puntos clave”INTes la señal deCtrl+C(también válidoSIGINTo el número2).- El
trapse registra al principio del script, antes del flujo principal. - Dentro de la función se debe llamar a
exit; si no, el script continúa tras la interrupción. tput civisoculta el cursor ytput cnormlo restaura. Si se oculta, hay que restaurarlo siempre al salir.- La función de limpieza es el lugar para borrar ficheros temporales o detener procesos lanzados por el script.
Limpieza completa
Section titled “Limpieza completa”tmp=$(mktemp)
function ctrl_c(){ echo -e "\n[!] Interrumpido" rm -f "$tmp" tput cnorm exit 130 # 128 + 2 (SIGINT)}
trap ctrl_c INTIgnorar y restaurar
Section titled “Ignorar y restaurar”trap '' INT # ignorar Ctrl+C (no recomendado de forma general)trap - INT # restaurar el comportamiento por defectotrap -p # listar los traps activosSeñales y trap EXIT
Section titled “Señales y trap EXIT”Una señal es un aviso que el sistema envía a un proceso.
| Señal | Número | Origen / efecto |
|---|---|---|
HUP |
1 | Cierre de la terminal; muchos servicios recargan configuración |
INT |
2 | Ctrl+C |
QUIT |
3 | Ctrl+\ (termina y genera volcado) |
KILL |
9 | Terminación forzosa; no se puede capturar |
USR1 / USR2 |
10 / 12 | Definidas por la aplicación |
TERM |
15 | Terminación ordenada (valor por defecto de kill) |
CONT |
18 | Reanuda un proceso detenido |
STOP |
19 | Detiene el proceso; no se puede capturar |
TSTP |
20 | Ctrl+Z (suspensión desde teclado) |
trap -l # lista de señales disponiblesLos números corresponden a Linux en arquitecturas habituales.
Varias señales
Section titled “Varias señales”trap limpiar INT TERM HUPtrap EXIT
Section titled “trap EXIT”Se ejecuta siempre que el script termine: finalización normal, exit, error o señal capturada.
function limpiar(){ rm -f "$tmp" tput cnorm}
tmp=$(mktemp)trap limpiar EXITPatrón recomendado: EXIT para la limpieza y INT/TERM solo para convertir la señal en un exit:
trap limpiar EXITtrap 'exit 130' INTtrap 'exit 143' TERMOtros traps
Section titled “Otros traps”trap 'echo "Error en la línea $LINENO" >&2' ERR # al fallar un comando (con set -e o -E)trap 'echo "Recargando"' USR1 # reaccionar a una señal personalizadaProcesos: ps, top, kill
Section titled “Procesos: ps, top, kill”Listar procesos
Section titled “Listar procesos”ps aux # todos los procesos con detalleps -ef # formato alternativo, incluye PPIDps aux | grep nginx # buscar uno concretops -p 1234 -o pid,ppid,cmd # proceso concretopgrep -a nginx # PIDs y comandos que coinciden con el nombrepidof nginx # PIDs por nombre exactotop # monitor interactivo (q para salir)htop # versión mejorada, si está instaladoEnviar señales
Section titled “Enviar señales”kill 1234 # SIGTERM (terminación ordenada)kill -15 1234 # equivalentekill -9 1234 # SIGKILL (último recurso)kill -HUP 1234 # otra señal por nombrekill -l # lista de señales
pkill nginx # por nombrepkill -f "script.sh" # por línea de comandos completakillall nginx # todos los procesos con ese nombreSe prueba primero TERM para que el proceso pueda cerrarse limpiamente y solo se usa KILL si no responde.
Comprobar si un proceso existe
Section titled “Comprobar si un proceso existe”if kill -0 "$pid" 2>/dev/null; then echo "El proceso $pid sigue vivo"fiInformación en /proc
Section titled “Información en /proc”cat /proc/$$/cmdline # línea de comandos del proceso actualls -l /proc/$$/fd # descriptores abiertoscat /proc/loadavg # carga del sistemaVariables relacionadas
Section titled “Variables relacionadas”| Variable | Contenido |
|---|---|
$$ |
PID del script |
$PPID |
PID del proceso padre |
$! |
PID del último proceso en segundo plano |
Segundo plano: &, jobs, fg, bg
Section titled “Segundo plano: &, jobs, fg, bg”Lanzar en segundo plano
Section titled “Lanzar en segundo plano”sleep 60 & # con & al finalecho "PID: $!" # PID del proceso lanzadoSuspender y reanudar
Section titled “Suspender y reanudar”sleep 300 # proceso en primer plano# Ctrl+Z -> queda detenidojobs # lista de trabajos de la sesiónbg %1 # reanuda el trabajo 1 en segundo planofg %1 # lo trae a primer planokill %1 # termina el trabajo 1| Comando | Efecto |
|---|---|
jobs |
Lista los trabajos de la terminal actual |
fg %N |
Trae el trabajo N a primer plano |
bg %N |
Continúa el trabajo N en segundo plano |
disown %N |
Desvincula el trabajo de la terminal (sobrevive al cierre) |
wait |
Espera a que terminen los procesos hijo |
Redirigir la salida del proceso en segundo plano
Section titled “Redirigir la salida del proceso en segundo plano”comando > salida.log 2>&1 &Un proceso en segundo plano que escribe en la terminal interfiere con lo que se escribe después.
wait y ejecución en paralelo
Section titled “wait y ejecución en paralelo”comando_lento &pid=$!echo "Haciendo otras cosas..."wait "$pid" # espera a ese procesoecho "Código de salida: $?"wait sin argumentos espera a todos los hijos.
Lanzar varias tareas en paralelo
Section titled “Lanzar varias tareas en paralelo”function procesar(){ echo "Inicio $1" sleep 2 echo "Fin $1"}
for i in 1 2 3 4; do procesar "$i" &donewaitecho "Todo terminado"Limitar el número de tareas simultáneas
Section titled “Limitar el número de tareas simultáneas”max=4for i in {1..20}; do procesar "$i" & while (( $(jobs -r | wc -l) >= max )); do sleep 0.2 donedonewaitCon xargs -P
Section titled “Con xargs -P”printf '%s\n' {1..20} | xargs -P 4 -I{} sh -c 'echo "Tarea {}"; sleep 1'cat hosts.txt | xargs -P 8 -I{} ping -c1 -W1 {}Recoger resultados de cada tarea
Section titled “Recoger resultados de cada tarea”declare -A pidsfor h in 192.0.2.1 192.0.2.2; do ping -c1 -W1 "$h" &>/dev/null & pids[$h]=$!done
for h in "${!pids[@]}"; do if wait "${pids[$h]}"; then echo "$h responde"; else echo "$h no responde"; fidonenohup, timeout y lockfiles
Section titled “nohup, timeout y lockfiles”Evita que el proceso muera cuando se cierra la terminal (señal HUP).
nohup ./script_largo.sh > salida.log 2>&1 &Si no se redirige, la salida se guarda en nohup.out. Otras opciones para sesiones persistentes: tmux y screen.
timeout
Section titled “timeout”Limita el tiempo de ejecución de un comando.
timeout 5 ping 192.0.2.1 # termina a los 5 segundostimeout -s KILL 10 comando # con otra señaltimeout 3 bash -c 'echo > /dev/tcp/192.0.2.1/22' && echo "abierto"
timeout 5 comandoecho $? # 124 si se agotó el tiempoEvitar ejecuciones simultáneas: lockfile
Section titled “Evitar ejecuciones simultáneas: lockfile”Con flock (recomendado, el bloqueo se libera solo al terminar):
exec 9> /tmp/mi_script.lockif ! flock -n 9; then echo "Ya hay otra instancia en ejecución" >&2 exit 1fi
# ... resto del script ...Con un directorio como cerrojo (mkdir es atómico):
lock="/tmp/mi_script.lock"if ! mkdir "$lock" 2>/dev/null; then echo "Ya hay otra instancia en ejecución" >&2 exit 1fitrap 'rmdir "$lock"' EXITReintentos con espera
Section titled “Reintentos con espera”for intento in {1..5}; do if comando_inestable; then break; fi echo "Intento $intento fallido, reintentando..." >&2 sleep $((intento * 2))doneEjecutar con prioridad baja
Section titled “Ejecutar con prioridad baja”nice -n 10 ./tarea_pesada.shrenice -n 10 -p 1234