Angenommen, ich habe ein Skript wie das folgende
#!/usr/bin/env zsh
./subscript.sh &
# do stuff
...
# do more stuff
Ich möchte, dass der laufende Prozess subscript.sh
(und alle von ihm initiierten Prozesse) immer dann vollständig beendet werden, wenn:
- Das obige Skript wird beendet
- Das obige Skript wird aus irgendeinem Grund beendet.
Wie kann ich das oben genannte durchsetzen? Wird dies automatisch von der Shell übernommen?
Antwort1
Die Shell wird ihre Unterprozesse definitiv nicht spontan beenden – schließlich soll ein Hintergrundjob im Hintergrund laufen und sich nicht um das Leben seines übergeordneten Prozesses kümmern. (Eine interaktive Shell wird unter Umständen ihre Unterprozesse beenden, wenn sie beendet wird – was nicht immer wünschenswert ist, dahernohup
.)
Sie können das Shell-Skript so einstellen, dass es seine Hintergrundjobs beendet, wenn es beendet wird oder durch ein abfangbares Signal beendet wird. Notieren Sie die Prozess-IDs der Jobs und beenden Sie sie über eine Trap. Beachten Sie, dass dadurch nur die Jobs beendet werden (also der ursprüngliche Prozess, der im Hintergrund gestartet wurde), nicht aber deren Unterprozesse.
jobs=()
trap '((#jobs == 0)) || kill $jobs' EXIT HUP TERM INT
…
subscript1 & jobs+=($!)
subscript2 & jobs+=($!)
…
Wenn Sie sicher sein möchten, dass alle Prozesse und ihre Unterprozesse beendet werden, ist mehr Planung erforderlich. Eine Methode besteht darin, dafür zu sorgen, dass alle Prozesse eine eindeutige Datei geöffnet haben. Um sie alle zu beenden, beenden Sie alle Prozesse, die diese Datei geöffnet haben. Ein Unterprozess kann entkommen, indem er die Datei schließt.
#!/bin/sh
lock_file=$(mktemp)
exec 3<"$lock_file"
your_script
status=$?
exec 3<&-
fuser -k "$lock_file"
exit $status
Antwort2
Sie könnten EXIT abfangen und ein Signal an die Prozessgruppe des Skripts senden.
unter Linux
trap 'kill -SIGTERM 0' EXIT
unter FreeBSD
trap 'kill -15 -$$' EXIT
SIGKILL
ist das einzige Signal, bei dem dies nicht funktionieren würde, da das Skript bedingungslos beendet wird.