2009-10-29 13 views
13

Dla celów testowych mam ten skryptTerminate uruchomione polecenia, gdy skrypt zostanie zabity

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

Running to z interaktywnym terminalu, Ctrl + C wygaśnie bash i polecenia find.

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

Uruchomienie go w tle i zabicie powłoki spowoduje osierocenie poleceń uruchomionych w skrypcie.

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

Chcę, aby ten skrypt powłoki zakończył wszystkie procesy potomne, gdy kończy działanie, niezależnie od sposobu wywołania. Zostanie on ostatecznie uruchomiony z aplikacji python i java - a po zakończeniu działania skryptu potrzebna jest pewna forma czyszczenia - wszelkie opcje, które powinienem rozważyć lub w jakikolwiek sposób przepisać skrypt, aby oczyścić się przy wyjściu?

Odpowiedz

15

bym zrób coś takiego:

#!/bin/bash 
trap : SIGTERM SIGINT 

echo $$ 

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

wait $FIND_PID 

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

Pewne wyjaśnienie jest w porządku, jak sądzę. Po bramie musimy zmienić domyślną obsługę sygnału. : jest poleceniem no-op, ponieważ przekazanie pustego łańcucha powoduje, że powłoka ignoruje sygnał, zamiast coś z nim robić (przeciwieństwo tego, co chcemy zrobić).

Następnie, komenda find jest uruchamiana w tle (z perspektywy skryptu) i wywołujemy wbudowaną wersję wait, aby zakończyć. Ponieważ przekazaliśmy rzeczywistą komendę do powyższej trap, gdy przetwarzany jest sygnał, wait zakończy działanie ze stanem większym niż 128. Jeśli proces zostanie zakończony, wait zwróci status wyjścia tego procesu.

Na koniec, jeśli wait zwróci ten status błędu, chcemy przeprowadzić proces potomny kill. Na szczęście uratowaliśmy jego PID. Zaletą tego podejścia jest to, że można zarejestrować komunikat o błędzie lub w inny sposób zidentyfikować, że sygnał spowodował wyjście skryptu.

Jak już wspomnieli inni, wprowadzenie kill -- -$$ jako argumentu do trap jest inną opcją, jeśli nie zależy ci na pozostawieniu jakichkolwiek informacji wokół post-wyjścia.

Dla trap pracować tak, jak chcesz, to musisz powiązać go z wait - strona bash człowiek mówi: „Jeśli bash czeka na polecenia do wykonania i odbiera sygnał dla których trap został ustawiony, trap nie zostanie wykonany, dopóki polecenie nie zostanie zakończone. " wait to sposób obejścia tego czkawki.

Jeśli chcesz, możesz go rozszerzyć na więcej procesów podrzędnych. Tak naprawdę nie testowałem tego wyczerpująco, ale wygląda na to, że działa tutaj.

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

Konwencjonalne polecenie "no-op" to "': "". – ephemient

+0

Hot. Zmieniam to teraz. –

+0

Jeśli uruchomię proces w tle, to nie zostanie on zabity. Jeśli nie uruchomię go w tle, proces potomny zostanie zabity –

0

To, co musisz zrobić, to zatrzymać sygnał zabicia, zabić polecenie znalezienia i wyjść.

+3

'kill' domyślnie wysyła' SIGTERM'. "SIGKILL" jest nie do odegrania. –

1

Wystarczy dodać taką linię do skryptu:

trap "kill $$" SIGINT 

Być może trzeba zmienić „SIGINT” do „INT” w konfiguracji, ale to po prostu zabić proces i wszystkie procesy potomne, kiedy naciśnij Ctrl-C.

+2

zamiast "kill $$", prawdopodobnie powinieneś wysłać TERM do pid polecenia find! –

+1

'$!' Może, chociaż prawdopodobnie chcesz mieć lepszą kontrolę. – ephemient

6

Wysyła sygnał do grupy. Więc zamiast kill 13231 zrobić:

kill -- -13231 

Jeśli zaczynasz od pytona następnie rzucić okiem na: http://www.pixelbeat.org/libs/subProcess.py który pokazuje, jak naśladować powłoki rozpoczęciem i zabija grupę

+0

Czy każde polecenie w tym skrypcie będzie należało do tej grupy procesów? – nos

+0

Jeśli zaczniesz od powłoki tak, w przeciwnym razie będziesz musiał zacząć jak w subProcess.py – pixelbeat

+0

Nie zawsze masz kontrolę nad sposobem, w jaki twoje skrypty zostaną zakończone. – ndemou

7

Szukałem eleganckiego rozwiązania tego problemu i znalazłem następujące rozwiązanie w innym miejscu.

trap 'kill -HUP 0' EXIT 

Własne strony man nic nie mówią o tym, co 0 środki, ale od kopania wokół, wydaje się oznaczać aktualną grupę procesów. Ponieważ skrypt dostaje swoją własną grupę procesów, kończy się to wysyłaniem SIGHUP do wszystkich dzieci skryptu, pierwszego planu i tła.

+0

Wydaje się, że działa to ładnie (próbowałem przez zabicie skryptu za pomocą ctrl-C i zamknięcie terminala), ale boję się ukrytych wad. Jakiś guru basha chcący podzielić się swoją opinią? – ndemou

+0

http://stackoverflow.com/a/22644006/301717 sugerują podobną odpowiedź, ale wydają się bardziej niezawodne – Jezz

1

@ Patryka odpowiedź prawie załatwiło sprawę, ale to nie działa, jeśli rodzic proces swojej bieżącym skorupy znajduje się w tej samej grupie (to zabija rodziców też).

Znalazłem to być lepiej:

trap 'pkill -P $$' EXIT

Zobacz here aby uzyskać więcej informacji.

Powiązane problemy