Qué esta pasando
Cuando presiona Ctrl+ C, la SIGINT
señal se entrega a todo el grupo de procesos en primer plano . Aquí se envía tanto al find
proceso como al proceso de shell de llamada. find
reacciona saliendo inmediatamente, y el caparazón reacciona llamando a la trampa.
Si el código en la trampa regresa (es decir, no llama exit
), la ejecución continúa con el comando después del que fue interrumpido por la señal. Aquí, después de que el find
comando llega al final del script, el script se cierra inmediatamente de todos modos. Pero puede ver la diferencia entre ingresar 0 y 1 agregando otro comando:
find /
echo "find returned $?"
Una forma de hacer lo que quieres (pero probablemente no deberías hacer)
Puedes hacer lo que quieras; pero esta parte de mi respuesta es más sobre descubrir la programación de shell que resolver un problema real.
- Como cuestión de diseño, una señal reiniciable no es lo que normalmente esperaría en el tipo de programas relativamente simples que normalmente son los scripts de shell. La expectativa es que Ctrl+ Cmatará el script.
- Como verá a continuación, de todos modos, extiende las capacidades del shell un poco lejos.
Si desea evitar la muerte find
, lo que necesita para iniciarlo en el fondo : find / &
. Luego use el wait
incorporado para esperar a que salga normalmente. Una señal interrumpirá el wait
incorporado, que puede ejecutar en un bucle hasta que reciba una señal que desea propagar. Luego úsalo kill
para matar el trabajo.
hell () {
echo "Do you want to quit? Press 1 for yes and 0 for no"
read n
if [ "$n" = 1 ]; then
# Kill the job if it's running, then exit
if [ -n "$job_pid" ]; then kill $job_pid; fi
exit 1
fi
}
job_pid=
trap "hell" SIGINT
# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
echo "resuming wait"
done
job_pid=
echo last exit code: $?
Existen limitaciones para este enfoque en el shell:
- Hay una condición de carrera: si presiona Ctrl+ Cjusto después de que el trabajo haya terminado pero antes de la
job_pid=
línea, el controlador de señal intentará matar $jobpid
, pero el proceso ya no existe (incluso como un zombi, porque wait
ya lo ha cosechado), y el proceso La identificación puede haber sido reutilizada por otro proceso. Esto no se puede arreglar fácilmente en el shell (¿tal vez configurando un controlador para SIGCHLD
?).
- Si necesita el estado de devolución del trabajo, debe usar el
wait $job_pid
formulario. Pero entonces no se puede distinguir " wait
fue interrumpido por una señal" de "el trabajo fue cancelado por una señal" (ni de "el trabajo finalizó por sí solo con un estado de retorno ≥128", pero eso es un hecho general programación).
- Esto no se extenderá fácilmente si es que lo hace a múltiples subjobs. Tenga en cuenta que el comportamiento de las trampas y las señales a menudo es sorprendente cuando va más allá de lo básico en la mayoría de las implementaciones de shell (solo ksh lo hace bien).
Para superar estas limitaciones, use un lenguaje más sofisticado como Perl o Python.
Gilles 'SO- deja de ser malvado'
fuente