Ta odpowiedź na polecenie wiersza polecenia, aby automatycznie zabić polecenie po pewnym czasie
proponuje 1-liniową metodę przekroczenia limitu długo działającego polecenia z linii poleceń bash:
( /path/to/slow command with options ) & sleep 5 ; kill $!
Ale możliwe jest, że dane polecenie „długo działające” może zakończyć się przed upływem limitu czasu. (Nazwijmy to „zwykle długo działającym, ale czasem szybkim” poleceniem lub tlrbsf dla zabawy).
Więc to fajne podejście 1-liniowe ma kilka problemów. Po pierwsze, sleep
nie jest warunkowy, więc ustawia niepożądaną dolną granicę czasu potrzebnego na zakończenie sekwencji. Rozważ 30s, 2m lub nawet 5m na sen, kiedy komenda tlrbsf kończy się w ciągu 2 sekund - wysoce niepożądane. Po drugie, kill
jest bezwarunkowe, więc ta sekwencja będzie próbowała zabić niedziałający proces i narzekać na ten temat.
Więc...
Czy istnieje sposób na przekroczenie limitu czasu przez zwykle długo działające, ale czasem szybkie ( „tlrbsf” ) polecenie, które
- ma implementację bash (inne pytanie ma już odpowiedzi w Perlu i C)
- zakończy się wcześniejszym z dwóch: zakończenie programu tlrbsf lub upłynął limit czasu
- nie zabije nieistniejących / niedziałających procesów (lub opcjonalnie: nie narzeka na złe zabicie)
- nie musi być liniowcem 1-liniowym
- może działać pod Cygwin lub Linux
... a dla punktów bonusowych uruchamia komendę tlrbsf na pierwszym planie i dowolny proces „uśpienia” lub dodatkowy proces w tle, tak że stdin / stdout / stderr komendy tlrbsf może zostać przekierowany, tak jakby był uruchomić bezpośrednio?
Jeśli tak, udostępnij swój kod. Jeśli nie, proszę wyjaśnić dlaczego.
Spędziłem trochę czasu próbując zhakować powyższy przykład, ale osiągam limit moich umiejętności bashowych.
źródło
timeout
narzędzia GNU ?timeout
jest świetne! możesz nawet używać wielu poleceń (skrypt wieloliniowy): stackoverflow.com/a/61888916/658497Odpowiedzi:
Myślę, że właśnie o to prosisz:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
źródło
Prawdopodobnie szukasz
timeout
polecenia w coreutils. Ponieważ jest częścią coreutils, jest technicznie rozwiązaniem typu C, ale nadal jest coreutils.info timeout
po więcej szczegółów. Oto przykład:źródło
gtimeout
brew install coreutils
, a następnie można jej użyćgtimeout
.To rozwiązanie działa niezależnie od trybu monitorowania bash. Możesz użyć odpowiedniego sygnału, aby zakończyć polecenie
Obserwator zabija twoją komendę po upływie określonego czasu; skrypt czeka na wolne zadanie i kończy obserwatora. Zauważ, że
wait
nie działa z procesami, które są dziećmi innej powłoki.Przykłady:
źródło
wait
zwraca status zakończenia procesu, na który czeka. Więc jeśli twoje polecenie zakończy działanie w wyznaczonym czasie, ale z niezerowym statusem wyjścia, wówczas logika będzie zachowywać się tak, jak upłynął limit czasu, tjyour_command interrupted
. Drukuj . Zamiast tego mógłby zrobić towait
bez przeprowadzeniaif
, a następnie sprawdzić, czy$watcher
PID nadal istnieje, jeśli tak, to wiesz, że nie zrobił limitu czasu.kill
dzieje w jednym przypadku, alepkill
w drugim. Musiałem użyćpkill
obu, aby to działało poprawnie. Spodziewałbym się, że jeśli zapiszesz polecenie()
, będziesz musiał użyć go,pkill
aby je zabić. Ale może działa to inaczej, jeśli wewnątrz jest tylko jedno polecenie()
.Proszę bardzo:
możesz zmienić
SIGINT
i10
jak chcesz;)źródło
coreutils
pakiecie na FreeBSD.Możesz to zrobić całkowicie za pomocą
bash 4.3
i powyżej:_timeout 5 longrunning_command args
{ _timeout 5 producer || echo KABOOM $?; } | consumer
producer | { _timeout 5 consumer1; consumer2; }
Przykład:
{ while date; do sleep .3; done; } | _timeout 5 cat | less
Potrzebuje Bash 4.3 dla
wait -n
Jeśli nie potrzebujesz kodu powrotu, możesz to uczynić jeszcze prostszym:
Uwagi:
Ściśle mówiąc nie potrzebne
;
w; )
, jednak czyni rzeczy bardziej spójne z; }
-case. Iset +b
prawdopodobnie można go również zostawić, ale lepiej zabezpieczyć niż przepraszać.Z wyjątkiem
--forground
(prawdopodobnie) możesz zaimplementowaćtimeout
obsługę wszystkich wariantów .--preserve-status
jest jednak trochę trudny. Pozostaje to jako ćwiczenie dla czytelnika;)Ten przepis można zastosować „naturalnie” w skorupce (tak naturalnej jak dla
flock fd
):Jednak, jak wyjaśniono powyżej, nie można w ten sposób ponownie eksportować zmiennych środowiskowych do otaczającej powłoki w ten sposób.
Edytować:
Przykład ze świata rzeczywistego: Limit czasu
__git_ps1
w przypadku, gdy zajmuje to zbyt dużo czasu (np. Powolne łącza SSHFS):Edycja2: Bugfix. Zauważyłem, że
exit 137
nie jest to konieczne, a jednocześnie_timeout
zawodne.Edycja3:
git
jest bardzo trudna, więc potrzebuje podwójnej sztuczki, aby działać satysfakcjonująco.Edit4: Zapomniałem o
_
pierwszym_timeout
dla prawdziwego przykładu GIT.źródło
cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status.
Od: tiswww.case.edu/php/chet/bash/NEWSWolę „timelimit”, który ma pakiet przynajmniej w debianie.
http://devel.ringlet.net/sysutils/timelimit/
Jest nieco ładniejszy niż „limit czasu” coreutils, ponieważ drukuje coś po zabiciu procesu, a także domyślnie wysyła SIGKILL po pewnym czasie.
źródło
timelimit -t1 ./a_forking_prog
zabij tylko jeden z dwóch procesów), ale limit czasu działa.Aby przekroczyć limit czasu
slowcommand
po 1 sekundzie:timeout 1 slowcommand || echo "I failed, perhaps due to time out"
Aby ustalić, czy polecenie przekroczyło limit czasu, czy zakończyło się niepowodzeniem z własnych powodów, sprawdź, czy kod stanu to 124:
Zauważ, że gdy status wyjścia wynosi 124, nie wiesz, czy upłynął
timeout
limit czasu z powodu twojego polecenia, czy też samo polecenie zostało zakończone z powodu własnej wewnętrznej logiki przekroczenia limitu czasu, a następnie zwróciło 124. Możesz bezpiecznie założyć w obu przypadkach jednak nastąpił pewien czas.źródło
Zobacz także http://www.pixelbeat.org/scripts/timeout skrypt, którego funkcjonalność została zintegrowana z nowszymi coreutils
źródło
Trochę hacky, ale działa. Nie działa, jeśli masz inne procesy na pierwszym planie (pomóż mi to naprawić!)
Myślę, że można to odwrócić, spełniając kryteria „bonusu”:
źródło
limit czasu jest prawdopodobnie pierwszym podejściem do wypróbowania. W przypadku przekroczenia limitu czasu może być konieczne powiadomienie lub inne polecenie. Po kilku poszukiwaniach i eksperymentach wymyśliłem ten skrypt bash :
źródło
Prosty skrypt z przejrzystością kodu. Zapisz w
/usr/local/bin/run
:Przekroczono limit czasu polecenia, które działa zbyt długo:
Kończy się natychmiast po wykonaniu polecenia:
źródło
Jeśli znasz już nazwę programu (załóżmy
program
), aby zakończył się po upływie limitu czasu (jako przykładowe3
sekundy), mogę wnieść proste i nieco brudne alternatywne rozwiązanie:Działa to doskonale, jeśli nazywam procesy testowe wywołaniami systemowymi.
źródło
argv[0]
, być może z innymi hackami, aby zrobić więcej miejsca).(sleep 3 && docker stop <container>) &
działało ładnie. Dzięki!{ sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"
sposób : W ten sposób zabije tylko zadania w bieżącej powłoce.Jest też
cratimeout
Martin Cracauer (napisany w C dla systemów Unix i Linux).źródło
OS X nie używa jeszcze bash 4, nie ma też / usr / bin / timeout, więc oto funkcja, która działa na OS X bez home-brew lub macports, podobna do / usr / bin / timeout (na podstawie Tino's odpowiedź). Sprawdzanie poprawności parametrów, pomoc, użycie i obsługa innych sygnałów są ćwiczeniem dla czytelnika.
źródło
W 99% przypadków odpowiedzią NIE jest implementacja logiki przekroczenia limitu czasu. Logika Timeout jest w prawie każdej sytuacji czerwony znak ostrzegawczy, że coś innego jest nie tak i należy ustalić zamiast .
Czy czasami proces zawiesza się lub przerywa po n sekundach? Następnie dowiedz się, dlaczego i napraw to.
Nawiasem mówiąc, aby poprawnie rozwiązać problem z funkcją stragera, musisz użyć czekania „$ SPID” zamiast fg 1, ponieważ w skryptach nie masz kontroli zadań (a próba włączenia go jest głupia). Co więcej, fg 1 polega na tym, że nie zacząłeś wcześniej żadnych innych zadań w skrypcie, co jest złym założeniem.
źródło
Wystąpił problem z zachowaniem kontekstu powłoki i umożliwieniem przekroczenia limitu czasu, jedynym problemem jest to, że zatrzyma on wykonywanie skryptu po przekroczeniu limitu czasu - ale jest to zgodne z potrzebami, które mi przedstawiono:
z wyjściami:
oczywiście zakładam, że istniał reż
scripts
źródło
źródło
Mój problem był może trochę inny: uruchamiam polecenie przez ssh na zdalnej maszynie i chcę zabić powłokę i dziecko, jeśli polecenie się zawiesi.
Teraz używam następujących:
W ten sposób polecenie zwraca 255, gdy upłynął limit czasu lub kod powrotu polecenia w przypadku powodzenia
Należy pamiętać, że procesy zabijania z sesji ssh są obsługiwane inaczej niż interaktywna powłoka. Ale możesz również użyć opcji -t, aby ssh przydzielić pseudo terminal, więc działa on jak interaktywna powłoka
źródło
Oto wersja, która nie polega na spawnowaniu procesu potomnego - potrzebowałem samodzielnego skryptu, który osadził tę funkcjonalność. Wykonuje również ułamkowy interwał odpytywania, dzięki czemu można odpytywać szybciej. limit czasu byłby preferowany - ale utknąłem na starym serwerze
źródło
Bardzo uproszczony sposób:
przy pomocy pkill (opcja -f ) możesz zabić swoje polecenie za pomocą argumentów lub podać -n, aby uniknąć zabicia starego procesu.
źródło
Opierając się na odpowiedzi @ loup ...
Jeśli chcesz przekroczyć limit czasu procesu i wyciszyć wyjście kill / pid, uruchom:
Powoduje to umieszczenie procesu w tle w podpowłoce, dzięki czemu nie widać wyników zadania.
źródło
Mam zadanie crona, które wywołuje skrypt php i czasami utknie w skrypcie php. To rozwiązanie było dla mnie idealne.
Używam:
źródło
scripttimeout
?