Próbuję skonfigurować skrypt powłoki, aby uruchamiał procesy w tle, a kiedy Ctrlcwykonuję skrypt powłoki, zabija dzieci, a następnie kończy działanie.
Najlepsze, co udało mi się wymyślić, to to. Wygląda na to, że kill 0 -INT
również zabija skrypt, zanim nastąpi oczekiwanie, więc skrypt powłoki umiera przed ukończeniem przez dzieci.
Jakieś pomysły na to, jak sprawić, by ten skrypt powłoki czekał na śmierć dzieci po wysłaniu INT
?
#!/bin/bash
trap 'killall' INT
killall() {
echo "**** Shutting down... ****"
kill 0 -INT
wait # Why doesn't this wait??
echo DONE
}
process1 &
process2 &
process3 &
cat # wait forever
Odpowiedzi:
Twoje
kill
polecenie jest cofnięte.Podobnie jak wiele poleceń UNIX, opcje zaczynające się od minus muszą być na pierwszym miejscu, przed innymi argumentami.
Jeśli napiszesz
widzi to
-INT
jako opcję i wysyłaSIGINT
na0
(0
to specjalny numer oznaczający wszystkie procesy w bieżącej grupie procesów).Ale jeśli napiszesz
widzi
0
, decyduje, że nie ma więcej opcji, więc używaSIGTERM
domyślnie. I wysyła to do bieżącej grupy procesów, tak samo jak gdybyś to zrobił(próbowałby również wysłać
SIGTERM
do-INT
, co spowodowałoby błąd składniowy, ale wysyłaSIGTERM
do0
pierwszego i nigdy nie dociera tak daleko).Więc twój główny skrypt dostaje,
SIGTERM
zanim będzie mógł uruchomićwait
iecho DONE
.Dodaj
u góry, zaraz po
i uruchom go ponownie, aby to udowodnić.
Jak wskazuje Stephane Chazelas, dzieci w tle (
process1
itp.)SIGINT
Domyślnie będą ignorować .W każdym razie myślę, że wysyłanie
SIGTERM
byłoby bardziej sensowne.Wreszcie nie jestem pewien, czy
kill -process group
gwarantuje się, że najpierw pójdzie do dzieci. Ignorowanie sygnałów podczas wyłączania może być dobrym pomysłem.Spróbuj tego:
źródło
Niestety polecenia uruchamiane w tle są ustawiane przez powłokę tak, aby ignorowały SIGINT, a co gorsza, nie można ich zignorować
trap
. W przeciwnym razie wszystko, co musisz zrobić, toPonieważ proces1 i proces2 otrzymałyby SIGINT po naciśnięciu Ctrl-C, ponieważ są one częścią tej samej grupy procesów, która jest grupą procesów pierwszego planu w terminalu.
Powyższy kod będzie działał z pdksh i zsh, które pod tym względem nie są zgodne z POSIX.
W przypadku innych powłok należy użyć czegoś innego, aby przywrócić domyślny moduł obsługi dla SIGINT, na przykład:
lub użyj innego sygnału, takiego jak SIGTERM.
źródło
Dla tych, którzy chcą zabić proces i czekać na jego śmierć, ale nie na czas nieokreślony :
Czeka maksymalnie 60 sekund na typ sygnału.
Ostrzeżenie: ta odpowiedź nie jest w żaden sposób związana z przechwytywaniem sygnału zabicia i wysyłaniem go.
Wybiera aplikację do zabicia według nazwy lub argumentów. Zachowaj nawiasy kwadratowe dla pierwszej litery nazwy aplikacji, aby uniknąć dopasowania samego grep.
Z pewnymi zmianami możesz bezpośrednio użyć PID lub prostszego
pidof process_name
zamiastps
instrukcji.Szczegóły kodu: Ostatecznym grepem jest uzyskanie PID bez końcowych spacji.
źródło
Jeśli chcesz zarządzać niektórymi procesami w tle, dlaczego nie korzystać z funkcji kontroli zadań bash?
źródło
Więc majstrowałem przy tym również. W Bash możesz definiować funkcje i robić z nimi wymyślne rzeczy. Ja i moi współpracownicy używamy
terminator
, więc do wykonania wsadowego zwykle odradzamy całą masę okien terminatora, jeśli chcemy zobaczyć wyniki (mniej eleganckie niżtmux
tabulatory, ale można użyć haha bardziej przypominającego GUI).Oto konfiguracja, którą wymyśliłem, a także przykład rzeczy, które możesz uruchomić:
Uruchamiam to
Edytuj @Maxim, właśnie zobaczyłem twoją sugestię, która sprawia, że ton jest prostszy! Dzięki!
źródło