Komenda GNU coreutils timeout
jest niezwykle przydatna w niektórych sytuacjach skryptowych, pozwalając na użycie danych wyjściowych polecenia, jeśli jest ono szybkie, i pomijanie, jeśli zajmie to zbyt dużo czasu.
Jak mogę przybliżyć podstawowe zachowanie timeout
przy użyciu tylko narzędzi określonych w POSIX?
(Myślę, że może to wiązać się z kombinacji wait
, sleep
, kill
i kto wie co jeszcze, ale być może brakuje mi łatwiejszy podejście).
shell-script
posix
timeout
Dzika karta
źródło
źródło
command & pid=$! ; sleep 5 && kill $pid
command
zakończy się szybko, istnieje niewielka szansa na ponownepid
użycie przez inny proces przed uruchomieniemkill
polecenia? Nie chciałbym tego w kodzie produkcyjnym ....timeout
programu i go użyć?Odpowiedzi:
Moje podejście byłoby takie:
Wykonaj polecenie jako proces w tle 1
Uruchom „timer nadzorujący” jako proces w tle 2
Skonfiguruj moduł obsługi, aby przechwytywał sygnał zakończenia w powłoce nadrzędnej
Poczekaj na zakończenie obu procesów. Proces, który kończy się jako pierwszy, wysyła sygnał zakończenia do rodzica.
Moduł obsługi pułapek rodzica zabija oba procesy w tle poprzez kontrolę zadań (jeden z nich został już z definicji zakończony, ale to zabicie będzie nieszkodliwym brakiem operacji, ponieważ nie używamy PID, patrz poniżej)
Próbowałem ominąć możliwy warunek wyścigu opisany w komentarzach, używając identyfikatorów kontroli zadań powłoki (które byłyby jednoznaczne w obrębie tej instancji powłoki), aby zidentyfikować procesy w tle do zabicia, zamiast systemowych PID.
Wynik dla
TIMEOUT=10
(polecenie kończy się przed watchdog):Wynik dla
TIMEOUT=1
(watchdog kończy się przed poleceniem):Wynik dla
TIMEOUT=5
(watchdog i polecenie kończą „prawie” jednocześnie):źródło
cleanup() { ...; }
i (b) kontrola zadań jest funkcją bash nieokreśloną przez POSIX (chociaż ksh i inni też ją mają). Niezły skrypt!timeout="$1"; shift
i(exec "$@"; echo "Command completed"; kill $$)
zamiast jej zmieniać.