it-swarm.com.de

Was ist eine einfache Möglichkeit, einen Befehl 5 Minuten lang auszuführen?

Gibt es eine einfache Möglichkeit, einen bestimmten Befehl (der nur über Ctrl-C beendet werden kann) automatisch 5 Minuten lang auszuführen?

Zum Beispiel:

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

oder ein anderer Befehl, der sich nicht selbst beendet.

Ich möchte ein Zeitlimit festlegen können, nicht nur 5 Minuten.

64
eckhart

Es gibt (mindestens) zwei Programme, die diese Funktionalität bereitstellen:

NAME

timelimit - Begrenzen Sie effektiv die absolute Ausführungszeit eines Prozesses

ZUSAMMENFASSUNG

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

und

NAME

timeout - einen zeitlich begrenzten Befehl ausführen

ZUSAMMENFASSUNG

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

Sie sind wie folgt verpackt:

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

Vergleich:

/-----------------------------+------------+----------------\
|            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)       |
\-----------------------------+------------+----------------/

Anmerkungen:

  1. timeout verwendet immer SIGKILL als letztes Signal.
  2. timeout hat keine Funktionalität, um mit einem Signal zu beenden, wenn das untergeordnete Programm dies tut.

Der Exit-Status der beiden Programme ist unterschiedlich, lässt sich aber nur schwer übersichtlich zusammenfassen. Ich empfehle daher, dass Sie die Handbuchseiten selbst zu Rate ziehen.

Da timeout standardmäßig auf mehreren Systemen installiert ist (coreutils ist ein Standardpaket in vielen Distributionen), empfehle ich Ihnen, dies zu verwenden, es sei denn, Sie benötigen die zusätzlichen Funktionen von timelimit.

65
Toby Speight

Tatsächlich ist dies, wofür timeout ist:

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.

[email protected]:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout
87
Gombai Sándor

Reine bash eingebaut, ohne Coreutils

Ich fand heraus, dass diese Lösung in bash funktioniert, wobei ein eingebauter Befehl verwendet wird, ohne eine externe ausführbare Datei aufzurufen. Es funktioniert auf Systemen, auf denen eventuell noch nicht einmal die coreutils installiert sind [ 1 ]

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

Erklärungen : Wie üblich, wenn Sie einen Befehl mit & im Hintergrund senden, wird seine PID in der internen Variablen $! gespeichert (in der modernen Version von dash vorhanden). , csh, bash, tcsh, zsh...).
Was wirklich den Unterschied zwischen den Shells ausmacht, ist das Vorhandensein des eingebauten Befehls read[ 2 ] und der Option -t. In der 1. Version wird der Befehl abgebrochen und ein Fehlerrückgabecode generiert, wenn der Benutzer eine Eingabezeile nicht vor der angegebenen Anzahl von Sekunden abschließt.

- t TIMEOUT Verursacht eine Zeitüberschreitung beim Lesen und gibt einen Fehler zurück, wenn eine vollständige Eingabezeile nicht innerhalb von TIMEOUT Sekunden gelesen wird.

Die zweite Version funktioniert wie die erste, aber Sie können die Abschaltzeit abbrechen, indem Sie einfach auf drücken enter.
In der Tat führt der Operator oder || die Anweisung kill nur dann aus, wenn der Befehl read mit einem anderen Rückkehrcode als Null beendet wird, als wenn das Zeitlimit abgelaufen ist. Wenn Sie drücken enter vor diesem Moment wird 0 zurückgegeben und der vorherige Befehl wird nicht beendet.


Coreutils-Lösungen [ 1 ]

Wenn coreutils auf Ihrem System vorhanden sind und Sie nicht die Zeit und die Ressourcen sparen müssen, um ein externes Programm aufzurufen, sind timeout und sleep die beiden perfekten Möglichkeiten, um Ihr Ziel zu erreichen.

timeout Die Verwendung von timeout ist unkompliziert.
Eventuell können Sie auch die Option -k verwenden, um ein zusätzliches Kill-Signal zu senden, wenn das erste fehlschlägt.

timeout 5m YourCommand                                         # 3rd version 

sleep Mit sleep können Sie Ihre Fantasie anwenden oder sich inspirieren lassen[]. Beachten Sie, dass Sie Ihren Befehl im Hintergrund oder im Vordergrund belassen können (z. B. muss sich top normalerweise im Vordergrund befinden).

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

Erklärungen

  • In der 4. Version führen Sie im Hintergrund YourCommand und dann Ihre Shell sleeps für 5 Minuten aus. Nach Abschluss des Vorgangs wird der letzte Hintergrundprozess ($!) abgebrochen. Sie stoppen Ihre Shell.
  • In der 5. Version führen Sie stattdessen im Hintergrund YourCommand aus und speichern diese PID sofort in der Variablen $pid. Dann führen Sie im Hintergrund ein Nickerchen von 5 Minuten und den darauf folgenden Befehl aus, der die gespeicherte PID löscht. Da Sie diese Befehlsgruppe im Hintergrund gesendet haben, stoppen Sie Ihre Shell nicht. Sie müssen die PID in einer Variablen speichern, da der Wert von $! durch die spätere Ausführung eines anderen Programms im Hintergrund aktualisiert werden kann. Mit einfachen Worten vermeiden Sie das Risiko, den falschen Prozess oder gar keinen Prozess zu töten .
  • In der 6. Version wird es eine neue Bash-Shell genannt, die sich in 5 Minuten mit $$ selbst tötet. Dann wird Ihr Befehl ausgeführt, der im Vordergrund bleibt.
  • In der 7. Version wird eine Subshell () aufgerufen, die ihre PID in einer Variablen (cmdpid) speichert und sich mit einer anderen Subshell beendet, die bei der Ausführung im Hintergrund gesendet wird. Führen Sie dann YourCommand im Vordergrund aus.

Natürlich können Sie in jeder Version das Kill-Signal, das Sie benötigen, vom Standard-Signal bis zum extremen kill -9 senden, um es nur dann zu verwenden, wenn es wirklich benötigt wird.

Referenzen

  • [ 1 ] Die Coreutils
  • [ 2 ] Das Handbuch für Bash-Anfänger
  • [] Die BashFAQ
15
Hastur

In Ihrem speziellen Fall unterstützen die meisten Implementierungen von ping-c oder --count so, dass sie nach einer bestimmten Anzahl von Pings enden:

ping -c 300 Host.example.com

Eine allgemeinere Lösung finden Sie in den anderen Antworten.

10
Toby Speight

Sie können dies mit einem einfachen Skript wie dem folgenden tun:

#!/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

(Signal SIGINT = 2 gemäß dem Vorschlag von Matija Nalis im Kommentar unten).

Eine Erklärung des (ungewöhnlichen?) Bash-Ausdrucks [email protected]:...: Die Positionsparameter ($*, [email protected], "$*", "[email protected]") lassen zum Beispiel die folgende zusätzliche Spezifikation zu:

"${@:START:COUNT}"

was bedeutet: von allen Parametern wird COUNT genommen, wobei der erste an der START-Position genommen wird; Wenn COUNT weggelassen wird, nehmen Sie alle bis zum Ende, beginnend mit der START-Position. Denken Sie daran, dass $0 der Programmname ist. Wenn START negativ ist, beginnen Sie mit der Zählung am Ende und denken Sie daran, dass COUNT nicht negativ sein kann , daher lautet das letzte Argument "${@:-1}". Außerdem müssen die Positionsparameter in doppelten Anführungszeichen fast immer eingeschlossen werden.

8
MariusMatutiae

Da Sie in Ihrem Beispiel ping erwähnen; Dieser Befehl hat einige Optionen, um nach einer bestimmten Zeit anzuhalten:

  • w deadline Geben Sie eine Zeitüberschreitung in Sekunden an, bevor ping beendet wird, unabhängig davon, wie viele Pakete wurden gesendet oder empfangen. In diesem Fall stoppt ping nicht nach dem Senden von count Paketen, sondern wartet auf deadline verfallen oder bis Anzahl Tests beantwortet wurden oder für eine Fehlermeldung vom Netzwerk.
  • W timeout Wartezeit auf eine Antwort in Sekunden. Die Option wirkt sich nur auf das Timeout aus, wenn keine Antworten vorliegen. Andernfalls wartet ping auf zwei RTTs.

- man ping

4
user2428118