2009-10-29 9 views
13

Para propósitos de prueba tengo este script de shellcomandos de ejecución cuando shell script se mató

#!/bin/bash 
echo $$ 
find/>/dev/null 2>&1 

Correr esto desde un terminal interactivo, Ctrl + C terminará fiesta, y el comando find.

$ ./test-k.sh 
13227 
<Ctrl+C> 
$ ps -ef |grep find 
$ 

Ejecutarlo en segundo plano, y matar el shell solo huérfano los comandos que se ejecutan en el script.

$ ./test-k.sh & 
[1] 13231 
13231 
$ kill 13231 
$ ps -ef |grep find 
nos 13232  1 3 17:09 pts/5 00:00:00 find/
$ 

Quiero que este script de shell finalice todos sus procesos secundarios cuando se ejecute, independientemente de cómo se llame. Con el tiempo se iniciará desde una aplicación python y java, y se necesita alguna forma de limpieza cuando se cierra el script. ¿Alguna opción que deba buscarse o alguna forma de reescribir el script para limpiarse al salir?

Respuesta

15

lo haría hacer algo como esto:

#!/bin/bash 
trap : SIGTERM SIGINT 

echo $$ 

find/>/dev/null 2>&1 & 
FIND_PID=$! 

wait $FIND_PID 

if [[ $? -gt 128 ]] 
then 
    kill $FIND_PID 
fi 

Alguna explicación está en orden, supongo. Fuera de la puerta, tenemos que cambiar parte del manejo de señal predeterminado. : es un comando que no funciona, ya que pasar una cadena vacía hace que el shell ignore la señal en lugar de hacer algo al respecto (lo contrario de lo que queremos hacer).

A continuación, el comando find se ejecuta en segundo plano (desde la perspectiva del guión) y lo llamamos la orden interna wait a que termine. Dado que le dimos un comando real al trap anterior, cuando se maneja una señal, wait saldrá con un estado mayor que 128. Si el proceso wait ed se completa, wait devolverá el estado de salida de ese proceso.

Por último, si el wait devuelve ese estado de error, queremos kill el proceso secundario. Afortunadamente guardamos su PID. La ventaja de este enfoque es que puede registrar algún mensaje de error o identificar de otra manera que una señal provocó que la secuencia de comandos salga.

Como han mencionado otros, poner kill -- -$$ como argumento en trap es otra opción si no le importa dejar información después de la salida.

Para trap para trabajar de la manera deseada, sí es necesario para sincronizarlo con wait - la página bash hombre dice "Si bash está esperando una orden para completar y recibe una señal para la que un trap se ha establecido, el trap no se ejecutará hasta que el comando finalice ". wait es la forma de evitar este inconveniente.

Puede ampliarlo a más procesos secundarios si así lo desea. Realmente no probé esta exhaustivamente, pero parece funcionar aquí.

$ ./test-k.sh & 
[1] 12810 
12810 
$ kill 12810 
$ ps -ef | grep find 
$ 
+1

El comando no-op convencional es "': '". – ephemient

+0

Caliente. Cambiándolo ahora –

+0

Si ejecuto el proceso en segundo plano, no se destruye. Si no lo ejecuto en segundo plano, el proceso hijo engendrado se destruye –

0

Lo que necesitarías hacer es atrapar la señal de muerte, matar el comando de búsqueda y salir.

+3

'kill' envía' SIGTERM' de forma predeterminada. 'SIGKILL' no puede ser atrapado. –

1

Sólo tiene que añadir una línea como esta a su script:

trap "kill $$" SIGINT 

puede que tenga que cambiar 'SIGINT' a 'INT' de su configuración, pero esto básicamente va a matar a su proceso y todos los procesos hijo cuando presionar Ctrl-C.

+2

en lugar de 'kill $$', ¡probablemente debas enviar TERM al pid del comando find! –

+1

'$!' Tal vez, aunque es probable que desee un control más fino que eso. – ephemient

6

Enviar una señal al grupo. Así que en lugar de hacer kill 13231:

kill -- -13231 

Si vas a empezar a partir de pitón a continuación, echar un vistazo a: http://www.pixelbeat.org/libs/subProcess.py que muestra cómo imitar la cáscara en el inicio de y matando a un grupo

+0

¿Todos los comandos de este script pertenecen a ese grupo de procesos? – nos

+0

Si se inició desde un shell sí, de lo contrario tendrá que comenzar como hecho en subProcess.py – pixelbeat

+0

No siempre tiene control de la forma en que terminará su secuencia de comandos – ndemou

7

Estaba buscando una solución elegante a este problema y encontré la siguiente solución en otro lugar.

trap 'kill -HUP 0' EXIT 

Mis propias páginas man no dicen nada acerca de lo que 0 medios, pero a partir de excavar alrededor, que parece significar el grupo de proceso actual. Como el script tiene su propio grupo de procesos, esto termina enviando SIGHUP a todos los elementos secundarios, secundarios y de fondo del script.

+0

Esto parece funcionar muy bien (intentándolo matando el guión con ctrl-C y cerrando la terminal), pero me temo que hay deficiencias ocultas. ¿Algún bash guru dispuesto a compartir su opinión? – ndemou

+0

http://stackoverflow.com/a/22644006/301717 sugieren una respuesta similar, pero parece más sólida – Jezz

1

@ respuesta de Patrick casi hizo el truco, pero no funciona si el padre proceso de su actual cáscara está en el mismo grupo (que mata a los padres también).

Me pareció que para ser mejor:

trap 'pkill -P $$' EXIT

Ver here para obtener más información.

Cuestiones relacionadas