Jaki jest prosty sposób na uruchomienie polecenia przez 5 minut? [duplikować]

66

To pytanie ma już odpowiedź tutaj:

Czy istnieje prosty sposób, aby określone polecenie (tylko przerywane Ctrl-C) działało automatycznie przez 5 minut?

Na przykład:

minute-command 5-minutes ping www.google.com

lub dowolne inne polecenie, które się nie kończy.

Chciałbym móc określić limit czasu, nie tylko 5 minut.

eckhart
źródło

Odpowiedzi:

67

Istnieją (co najmniej) dwa programy zapewniające tę funkcjonalność:

IMIĘ

timelimit - skutecznie ograniczać bezwzględny czas wykonania procesu

STRESZCZENIE

timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]

i

IMIĘ

timeout - uruchom polecenie z ograniczeniem czasowym

STRESZCZENIE

timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]

Są one pakowane w następujący sposób:

$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout

Porównanie:

/-----------------------------+------------+----------------\
|            Feature          |  timelimit |     timeout    |
+=============================+============+================+
|   time to run               | -t time    | first argument |
+-----------------------------+------------+----------------+
|   terminate signal          | -s signal  | -s signal      |
+-----------------------------+------------+----------------+
|   grace period              | -T time    | -k time        |
+-----------------------------+------------+----------------+
|   kill signal               | -S signal  | (note 1)       |
+-----------------------------+------------+----------------+
|   propagate signals         | -p         | (note 2)       |
\-----------------------------+------------+----------------/

Uwagi:

  1. timeoutzawsze używa SIGKILLjako sygnału ostatecznego.
  2. timeout nie ma żadnej funkcji wyjścia z sygnałem, gdy program podrzędny to robi.

Status wyjścia tych dwóch programów jest różny, ale trudno to dokładnie podsumować, dlatego sugeruję, abyś sam zajrzał do stron podręcznika.

Ponieważ timeoutjest instalowany domyślnie na większej liczbie systemów ( coreutilsjest to standardowy pakiet w wielu dystrybucjach), sugeruję, abyś go używał, chyba że potrzebujesz dodatkowych funkcji zapewnianych przez timelimit.

Toby Speight
źródło
10
Dlaczego miałbyś używać jednego zamiast drugiego?
Brice M. Dempsey,
2
@ BriceM.Dempsey Na mojej lokalnej maszynie limit czasu jest obecny, ale limit czasu nie jest (chociaż jest dostępny z repozytorium). Tak więc, jeśli jeden z nich zostanie zainstalowany fabrycznie ... Poza tym, patrząc na podpisy metod, widzę, że robią różne rzeczy i mają różne przypadki użycia.
Benubird
Zauważ, że istnieją co najmniej dwie implementacje timelimit. Zobacz Jak mogę zabić proces i upewnij się, że PID nie został ponownie użyty, aby uzyskać więcej informacji na jego temat i przekroczeniu limitu czasu GNU.
sch
1
@ BriceM.Dempsey timeoutjest wliczone w GNU coreutils , timelimitnie jest. Możesz zainstalować żaden, jeden lub oba. Po drugie zgłaszane jest, że timelimit wykonuje polecenie i kończy odradzany proces po określonym czasie z danym sygnałem. Najpierw wysyłany jest sygnał „ostrzegawczy” , a następnie po upływie limitu czasu sygnał „zabijania”, podobny do sposobu działania init (8) przy wyłączaniu. Więc nawet inne zachowanie w środku .
Hastur
Ponieważ coreutils GNU są preinstalowane na każdym systemie GNU / Linux, timeoutjest to droga do tego.
rexkogitans
87

W rzeczywistości jest to po timeoutto:

TIMEOUT(1)                          User Commands                         TIMEOUT(1)

NAME
       timeout - run a command with a time limit

SYNOPSIS
       timeout [OPTION] DURATION COMMAND [ARG]...
       timeout [OPTION]

DESCRIPTION
       Start COMMAND, and kill it if still running after DURATION.

lx@lxtp:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
Gombai Sándor
źródło
16

Czysty bashwbudowany, bez rdzeni

Odkryłem, że to rozwiązanie działa w bashoparciu o wbudowane polecenie bez wywoływania zewnętrznego pliku wykonywalnego. Działa na systemie, na którym ostatecznie nie są nawet zainstalowane coreutils [ 1 ]

YourCommand & read -t 300 ;  kill $!                           # 1st version
YourCommand & read -t 300 || kill $!                           # 2nd version 

Objaśnienia : jak zwykle po wysłaniu komendy w tle z &jego PID jest przechowywany w zmiennej wewnętrznej $!(obecne w nowoczesnej wersji dash, csh, bash, tcsh, zsh...).
To, co naprawdę robi różnicę między powłokami, to obecność wbudowanego polecenia read[ 2 ] i opcji -t. W pierwszej wersji, jeśli użytkownik nie wypełni wiersza wprowadzania przed określoną liczbą sekund, instrukcja zostanie zakończona i wygenerowany zostanie kod powrotu błędu.

-t TIMEOUT Powoduje przekroczenie limitu czasu odczytu i zwrócenie błędu, jeśli pełny wiersz danych wejściowych nie zostanie odczytany w ciągu TIMEOUT sekund.

Druga wersja działa jako pierwsza, ale możesz anulować limit czasu zabijania po prostu naciskając enter.
Rzeczywiście operator lub ||wykonuje killinstrukcję tylko wtedy, gdy readpolecenie zakończy działanie z kodem powrotu innym niż zero, tak jak po upływie limitu czasu. Jeśli naciśniesz enterprzed tym momentem, zwróci 0 i nie zabije twojego poprzedniego polecenia.


Rozwiązania Coreutils [ 1 ]

Gdy w twoim systemie znajdują się coreutils i nie musisz oszczędzać czasu i zasobów, aby wywołać program zewnętrzny, timeouti sleepoba są idealnymi sposobami na osiągnięcie celu.

timeoutKorzystanie z timeoutjest proste.
W końcu możesz rozważyć skorzystanie z -kopcji wysłania dodatkowego sygnału zabicia, jeśli pierwszy się nie powiedzie.

timeout 5m YourCommand                                         # 3rd version 

sleep Dzięki sleepniemu możesz wykorzystać swoją fantazję lub czerpać inspiracje [ 3 ] . Pamiętaj, że możesz pozostawić swoje polecenie w tle lub na pierwszym planie (np. topZwykle musi znajdować się na pierwszym planie).

YourCommand & sleep 5m; kill $!                                # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) &                # 5th Background

bash -c '(sleep 5m; kill $$) & exec YourCommand'               # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground

Objaśnienia

  • W czwartej wersji wykonujesz w tle, YourCommanda następnie twoja skorupa sleepprzez 5 minut. Kiedy zostanie zakończony, ostatni proces w tle ( $!) zostanie zabity. Zatrzymaj swoją skorupę.
  • W wersji 5 wykonujesz natomiast w tle YourCommandi od razu zapisujesz ten PID w zmiennej $pid. Następnie wykonujesz drzemkę w tle przez 5 minut i wynikające z niej polecenie, które zabije zapisany PID. Ponieważ wysłałeś tę grupę poleceń w tle, nie zatrzymujesz powłoki. Musisz zapisać PID w zmiennej, ponieważ wartość $!może zostać zaktualizowana przez ewentualne wykonanie innego programu w tle. Krótko mówiąc, unikasz ryzyka zabicia niewłaściwego procesu lub jego braku.
  • W szóstej wersji nazywa się to nową powłoką bash, która samobójczo za 5 minut $$, następnie wykonuje polecenie, które pozostaje na pierwszym planie.
  • W siódmej wersji wywoływana jest podpowłoka, ()która przechowuje swój PID w zmiennej ( cmdpid) i zabija się za pomocą innej podpowłoki wysyłanej w tle, a następnie uruchamia YourCommand na pierwszym planie.

Oczywiście w każdej wersji możesz wysłać potrzebny ci sygnał zabójstwa, od domyślnego do skrajnego kill -9 , do użycia tylko wtedy, gdy jest naprawdę potrzebny.

Bibliografia

  • [ 1 ] Coreutils
  • [ 2 ] Przewodnik dla początkujących Bash
  • [ 3 ] BashFAQ
Hastur
źródło
2
„Podczas snu możesz użyć swojej fantazji lub inspiracji [link do Bash FAQ]” +1 #thatsenoughinternetfortoday
joeytwiddle
11

W konkretnym przypadku większość implementacji pingwsparcia -club --countkończy się po określonej liczbie pingów:

ping -c 300 host.example.com

Aby uzyskać bardziej ogólne rozwiązanie, zobacz inne odpowiedzi.

Toby Speight
źródło
7
Mam wrażenie, że OP podał pingkonkretny przykład. Nie chce indywidualnych rozwiązań dla każdego innego programu.
user1717828,
8

Możesz to zrobić za pomocą prostego skryptu, takiego jak ten:

#!/bin/bash

#
# $1 is the time to let the program run, and $2, $3, ... are the command itself.
#

"${@:2}" &
PID=$!
sleep "${@:1:1}"
kill -2 $PID

(sygnał SIGINT = 2 zastosowany zgodnie z sugestią Matija Nalis w komentarzu poniżej).

Wyjaśnienie (nietypowego?) Wyrażenia bash $@:...: parametry pozycyjne, ( $*, $@, "$*", "$@") dopuszczają następującą dodatkową specyfikację, na przykład:

"${@:START:COUNT}"

co oznacza: ze wszystkich parametrów, weź COUNT z nich, pierwszy z nich to ten na pozycji START; jeśli pominięto COUNT, weź je wszystkie do końca, zaczynając od pozycji START. Pamiętaj, że $0to nazwa programu. Jeśli START jest ujemny, zacznij odliczanie od końca i pamiętaj, że COUNT nie może być ujemny, stąd ostatni argument "${@:-1}". Ponadto prawie zawsze uwzględniaj parametry pozycyjne w podwójnych cudzysłowach.

MariusMatutiae
źródło
1
Prawdopodobnie zaprojektowałbym skrypt tak, aby zajmował czas jako pierwszy lub ostatni argument i uruchamiał wszystkie pozostałe argumenty jako polecenie. Zezwolenie na dzielenie słów na bash $1jest dość obrzydliwe. Ponadto możesz po prostu sleep "$1"lub coś w tym countdown.
Peter Cordes,
1
@PeterCordes Gotowe, zgodnie z Twoimi życzeniami.
MariusMatutiae
Czas w pierwszym arg pozwala na to time=$1; shift, a następnie nie potrzebujesz składni krojenia tablic dla parametrów pozycyjnych. Ale tak, to o wiele prostsze.
Peter Cordes,
1
@PeterCordes zgodził się, ale poprosiłeś mnie o sprawdzenie, czy znałem bezpieczniejszy sposób na zrobienie tego i po prostu byłem leniwy, czy też byłem po prostu ignorantem. lol.
MariusMatutiae
ponieważ plakat konkretnie pytał o program, który można przerwać ctrl-c, prawdopodobnie lepiej jest spróbować kill -INTzamiast kill -9(lub przynajmniej spróbować -9po kilku sekundach, jeśli pierwszy nie spowodował błędu - daje to programowi szansę na czyste zamknięcie i nie pozostawianie plików tymczasowych itp. wokół)
Matija Nalis,
5

Ponieważ wspomniałeś pingw swoim przykładzie; to polecenie ma kilka opcji zatrzymania po określonym czasie:

  • w termin Określ limit czasu, w sekundach, przed zakończeniem działania polecenia ping niezależnie od liczby wysłanych lub odebranych pakietów. W tym przypadku ping nie zatrzymuje się po wysłaniu pakietu zliczania , czeka albo do upływu terminu, albo do momentu odebrania sond zliczania lub powiadomienia o błędzie z sieci.
  • Limit czasu W Czas oczekiwania na odpowiedź w sekundach. Ta opcja wpływa tylko na limit czasu przy braku odpowiedzi, w przeciwnym razie ping czeka na dwa RTT.

-man ping

użytkownik2428118
źródło