Hin und wieder kann es vorkommen, das ein Bash-Script eine oder mehrere Subshells öffnet, um diverse Jobs im Hintergrund zu erledigen. Dabei kann es aber in vielen Fällen vorkommen, dass eine der Subshells in einen Blocking-State verfällt und hängen bleibt. Das ist vor allem dann verhängnisvoll, wenn das Script automatisiert von beispielsweise CRON ausgeführt wird.
In solchen Szenarien empfiehlt es sich eine Routine zu implementieren, die beim Erreichen eines definierten Timeouts alle Subshells tötet.
Für diesen Fall bietet sich das Linux-Signal SIGALRM an. Wenn das Haupt-Script ein SIGALRM erhält, soll es alle seine Childs töten und sich mit ungleich Null beenden. So muss zusätzlich zu den Workern einfach nur eine weitere Subshell mit GNU/sleep + GNU/kill installiert werden, die nach Ablauf des Timeouts das Signal an den Hauptprozess sendet.
Hier ein Code-Schnipsel, der die Lösung erklärt:
#!/bin/bash
alarmtime=3
childs=3
parentpid=$$
childpids=()
exit_timeout() {
echo "Alarm signal received : killing all children"
for child in ${childpids[@]}; do
kill -STOP $childpid &>/dev/null
done
exit 1
}
trap exit_timeout SIGALRM
for i in $(seq $childs); do
sleep 4 & # very long task that may timeout
childpids+=($!)
done
(sleep $alarmtime; kill -ALRM $parentpid) &
alarmpid=$!
wait ${childpids[@]}
echo "Alarm never reached, children exited cleanly."
kill $alarmpid
Ich freue mich, wenn es jemandem hilft. =)