Bash
Usando "trampa" para reaccionar a señales y eventos del sistema
Buscar..
Sintaxis
- trap action sigspec ... # Ejecutar "action" en una lista de señales
- trap sigspec ... # La acción de omisión restablece las trampas para las señales
Parámetros
Parámetro | Sentido |
---|---|
-pag | Listar las trampas actualmente instaladas |
-l | Lista de nombres de señales y números correspondientes |
Observaciones
La utilidad de trap
es un shell especial incorporado. Se define en POSIX , pero bash también agrega algunas extensiones útiles.
Los ejemplos que son compatibles con POSIX comienzan con #!/bin/sh
, y los ejemplos que comienzan con #!/bin/bash
usan una extensión de bash.
Las señales pueden ser un número de señal, un nombre de señal (sin el prefijo SIG) o la palabra clave especial EXIT
.
Los garantizados por POSIX son:
Número | Nombre | Notas |
---|---|---|
0 | SALIDA | Ejecutar siempre en la salida de shell, independientemente del código de salida |
1 | SIGHUP | |
2 | SIGINT | Esto es lo que ^C envía |
3 | SIGQUIT | |
6 | SIGABRT | |
9 | SIGKILL | |
14 | SIGALRM | |
15 | Sigma | Esto es lo que kill envía por defecto |
La captura de SIGINT o Ctl + C
La captura se restablece para las subshells, por lo que el sleep
seguirá actuando sobre la señal SIGINT
enviada por ^C
(generalmente al salir), pero el proceso principal (es decir, el script de shell) no lo hará.
#!/bin/sh
# Run a command on signal 2 (SIGINT, which is what ^C sends)
sigint() {
echo "Killed subshell!"
}
trap sigint INT
# Or use the no-op command for no output
#trap : INT
# This will be killed on the first ^C
echo "Sleeping..."
sleep 500
echo "Sleeping..."
sleep 500
Y una variante que todavía le permite salir del programa principal presionando ^C
dos veces en un segundo:
last=0
allow_quit() {
[ $(date +%s) -lt $(( $last + 1 )) ] && exit
echo "Press ^C twice in a row to quit"
last=$(date +%s)
}
trap allow_quit INT
Introducción: limpiar archivos temporales
Puedes usar el comando de trap
para "atrapar" las señales; este es el equivalente de shell de la signal()
o sigaction()
llamada en C y la mayoría de los otros lenguajes de programación para capturar señales.
Uno de los usos más comunes de la trap
es limpiar archivos temporales tanto en una salida esperada como inesperada.
Desafortunadamente no hay suficientes scripts de shell hacer esto :-(
#!/bin/sh
# Make a cleanup function
cleanup() {
rm --force -- "${tmp}"
}
# Trap the special "EXIT" group, which is always run when the shell exits.
trap cleanup EXIT
# Create a temporary file
tmp="$(mktemp -p /tmp tmpfileXXXXXXX)"
echo "Hello, world!" >> "${tmp}"
# No rm -f "$tmp" needed. The advantage of using EXIT is that it still works
# even if there was an error or if you used exit.
Acumula una lista de trabajo de trampa para ejecutar en la salida.
¿Alguna vez ha olvidado agregar una trap
para limpiar un archivo temporal o hacer otro trabajo al salir?
¿Alguna vez has puesto una trampa que canceló otra?
Este código hace que sea fácil agregar las cosas que deben hacerse al salir de un elemento a la vez, en lugar de tener una declaración de trap
grande en algún lugar de su código, que puede ser fácil de olvidar.
# on_exit and add_on_exit
# Usage:
# add_on_exit rm -f /tmp/foo
# add_on_exit echo "I am exiting"
# tempfile=$(mktemp)
# add_on_exit rm -f "$tempfile"
# Based on http://www.linuxjournal.com/content/use-bash-trap-statement-cleanup-temporary-files
function on_exit()
{
for i in "${on_exit_items[@]}"
do
eval $i
done
}
function add_on_exit()
{
local n=${#on_exit_items[*]}
on_exit_items[$n]="$*"
if [[ $n -eq 0 ]]; then
trap on_exit EXIT
fi
}
Matando procesos infantiles en la salida
Las expresiones de captura no tienen que ser funciones o programas individuales, también pueden ser expresiones más complejas.
Al combinar los jobs -p
y kill
, podemos eliminar todos los procesos secundarios generados del shell en exit:
trap 'jobs -p | xargs kill' EXIT
reaccionar al cambiar el tamaño de la ventana de terminales
Hay una señal WINCH (WINdowCHange), que se activa cuando se cambia el tamaño de una ventana de terminal.
declare -x rows cols
update_size(){
rows=$(tput lines) # get actual lines of term
cols=$(tput cols) # get actual columns of term
echo DEBUG terminal window has no $rows lines and is $cols characters wide
}
trap update_size WINCH