Przygotuj skrypt jak poniżej:
#!/bin/bash
#
# run this script. don't run it if it's already running.
#
PIDFILE=/tmp/script.pid
LOGFILE=script.log
if [[ -f $PIDFILE ]]; then
echo "$PIDFILE exists. Not going to run..."
exit 0
fi
sleep 10m >> $LOGFILE 2>&1 &
PID=$!
echo $PID > $PIDFILE
trap "echo Exiting...; rm $PIDFILE; exit $?" INT TERM EXIT KILL
wait $PID
Wzywam ten skrypt, jak poniżej:
timeout 2m ./test_script
Po przekroczeniu limitu czasu lub Ctrl + C skrypt wypisuje dwukrotnie „Wyjście”.
# timeout 2m ./test_script
^CExiting...
Exiting...
rm: cannot remove `/tmp/script.pid': No such file or directory
Poniżej znajduje się wynik śledzenia i więcej danych:
# ps -ef | grep -v grep | egrep -i "sleep|time"
root 8571 4690 0 12:17 pts/0 00:00:00 timeout 2m ./test_script
root 8572 8571 0 12:17 pts/0 00:00:00 /bin/bash ./test_script
root 8573 8572 0 12:17 pts/0 00:00:00 sleep 10m
# cat /tmp/script.pid
8573
# strace -p 8571
Process 8571 attached - interrupt to quit
wait4(-1, 0x7fffc43fad4c, 0, NULL) = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---
kill(0, SIGINT) = 0
kill(0, SIGCONT) = 0
--- SIGCONT (Continued) @ 0 (0) ---
rt_sigreturn(0) = 61
--- SIGINT (Interrupt) @ 0 (0) ---
rt_sigreturn(0x2) = 61
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 8572
--- SIGCHLD (Child exited) @ 0 (0) ---
close(1) = 0
close(2) = 0
exit_group(0) = ?
Process 8571 detached
Czy ktoś może mi pomóc w zrozumieniu wewnętrznych przyczyn, dla których skrypt dwukrotnie wychwytuje sygnał, aby wydrukować „Wyjście ...” 2 razy?
linux
bash
bash-scripting
cog_n1t1v3
źródło
źródło
rm: cannot remove /tmp/script.pid: No such file or directory
<- wykonujeszecho "Exiting..."
dwa razy, czy na pewno potrzebujesz wszystkiegoINT TERM EXIT KILL
- czy to możliwe, że dwa z nich zostaną uruchomione - w tym samym czasie - po naciśnięciu CTRL-C?trap
. O ile skrypt musi przechwytywać wszystkie 4 określone sygnały, tak, potrzebuję ich wszystkich. Alternatywnie po prostu używam limitu czasu z poziomu mojego skryptu. Totimeout
KILL
, żeby się nie liczyć. Jeśli jednak uruchomię skrypt przy użyciu wersji bash 4.1.5, widzę tylko jedną wiadomość dlaTERM
(kiedy wychodzi) i nie ma wyjścia dlaINT
. Być może wersja bash ma znaczenie.Odpowiedzi:
Jeśli zastąpisz swoje
trap
oświadczenie tymi trzema liniami:dostaniesz wynik
z którego możemy wywnioskować
trap … TERM
Zestawienie powoduje, że powłoka wyłapania sygnału SIGTERM.timeout
Komenda wysyła proces SIGTERM (domyślnie), gdy upłynie czas. Więc powłoka łapie sygnał i wykonuje określone polecenie, w tymecho
,rm
(w twoim skrypcie) iexit
.trap … EXIT
oświadczenie powoduje, że powłoka pozostawia sobie karteczkę z napisem „pamiętaj, aby to zrobić, zanim pójdę do domu”. Tak więc, gdy pułapka SIGTERM wykonujeexit
polecenie, pułapka EXIT jest wykonywana.exit
polecenie, skrypt faktycznie kończy działanie, zamiast wykonywać pułapkę WYJŚCIE i przechodzić w piekło rekurencyjne.Jeśli wpiszesz Ctrl+ Cpodczas działania skryptu, otrzymasz pułapkę INT, a następnie pułapkę EXIT. Jeśli uruchomisz skrypt bez
timeout
limitu czasu lub z czasem oczekiwania dłuższym niż czas uśpienia, dostaniesz tylko pułapkę WYJŚCIA.Prawdopodobnie wystarczy powiedzieć
Uważam, że pułapka EXIT nie musi zostać wykonana
exit
, ponieważ wchodzisz w pułapkę EXIT wykonującexit
polecenie (w tym ukrytą na końcu skryptu), więc po zakończeniu wykonywania pułapki EXIT (echo
irm
) powłoka nie ma już nic do roboty poza wyjściem. Jedyne pytanie brzmi, z jakim statusem wyjściowym skrypt wychodzi. A jeśli zapisujesz jakąś wartość statusu wyjścia i to robiszrm $PIDFILE; exit $saved_status
, może to być interesujące. Ale dopóki mówiszrm $PIDFILE; exit $?
, skrypt prawdopodobnie zakończy działanie ze statusem wyjściarm
; i to prawdopodobnie nastąpi domyślnie, jeślirm
jest to ostatnie polecenie, które wykonasz.Zrobiłem kilka szybkich testów, które sugerowały, że można to pominąć
rozkaz, ale tego nie rozumiem. YMMV.
PS Jak powiedział Thomas,
trap … KILL
jest nieskuteczny.źródło