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

66

Diese Frage hat hier bereits eine Antwort:

Gibt es eine einfache Möglichkeit, einen bestimmten Befehl (nur durchführbar Ctrl-C) automatisch 5 Minuten lang ausführen zu lassen?

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.

eckhart
quelle

Antworten:

67

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. timeoutwird immer SIGKILLals letztes Signal verwendet.
  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 timeoutes standardmäßig auf mehreren Systemen installiert ist (dies coreutilsist ein Standardpaket in vielen Distributionen), empfehle ich Ihnen, dies zu verwenden, es sei denn, Sie benötigen die zusätzlichen Funktionen von timelimit.

Toby Speight
quelle
10
Warum würdest du eins lieber benutzen als das andere?
Brice M. Dempsey
2
@ BriceM.Dempsey Auf meinem lokalen Computer ist eine Zeitüberschreitung vorhanden, die zeitliche Begrenzung jedoch nicht (obwohl sie im Repository verfügbar ist). Also, wenn einer von ihnen vorinstalliert ist ... Abgesehen davon kann ich anhand der Methodensignaturen sehen, dass sie verschiedene Dinge tun und unterschiedliche Anwendungsfälle haben.
Benubird
Beachten Sie, dass es mindestens zwei Implementierungen von gibt timelimit. Siehe Wie kann ich einen Prozess beenden und sicherstellen, dass die PID nicht wiederverwendet wurde, um weitere Informationen zu diesen und zum GNU-Timeout zu erhalten?
sch
1
@ BriceM.Dempsey timeoutist in GNU coreutils enthalten , timelimitist es nicht. Sie können keine, eine oder beide installiert haben. Für die Sekunde wird gemeldet, dass timelimit einen Befehl ausführt und den erzeugten Prozess nach einer bestimmten Zeit mit einem bestimmten Signal beendet. Zuerst wird ein Warnsignal gesendet , dann nach einer Zeitüberschreitung ein Kill-Signal, ähnlich wie init (8) beim Herunterfahren arbeitet. Also noch ein anderes im mittleren Verhalten.
Hastur
Da GNU Coreutils auf jedem GNU / Linux vorinstalliert ist, timeoutist der Weg dorthin.
Rexkogitans
87

Eigentlich ist das, was timeoutist für:

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
quelle
16

Rein basheingebaut, ohne Coreutils

Ich fand heraus, dass diese Lösung bashauf einem eingebauten Befehl beruht, ohne eine externe ausführbare Datei aufzurufen. Es funktioniert auf Systemen, auf denen eventuell noch nicht einmal die Coreutils installiert wurden. [ 1 ]

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

Erläuterungen : wie immer , wenn Sie einen Befehl im Hintergrund senden mit &, seine PID in die interne Variable gespeichert $!(in der modernen Version von dash, 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 killAnweisung nur dann aus, wenn der readBefehl mit einem von Null verschiedenen Rückkehrcode beendet wird, als wenn das Zeitlimit abgelaufen ist. Wenn Sie entervor diesem Moment drücken , wird 0 zurückgegeben und der vorherige Befehl wird nicht beendet.


Coreutils-Lösungen [ 1 ]

Wenn auf Ihrem System Coreutils vorhanden sind und Sie nicht die Zeit und die Ressourcen zum Aufrufen eines externen Programms sparen müssen, timeoutund sleepbeides perfekte Möglichkeiten, um Ihr Ziel zu erreichen.

timeoutDie Verwendung timeoutist unkompliziert.
Möglicherweise können Sie auch die -kOption verwenden, ein zusätzliches Kill-Signal zu senden, wenn das erste fehlschlägt.

timeout 5m YourCommand                                         # 3rd version 

sleep Mit können sleepSie Ihre Fantasie nutzen oder sich inspirieren lassen [ 3 ] . Beachten Sie, dass Sie Ihren Befehl im Hintergrund oder im Vordergrund lassen können (z. B. muss topnormalerweise im Vordergrund sein).

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 YourCommanddann Ihre Shell sleeps für 5 Minuten aus. Wenn es fertig ist, wird der letzte Hintergrundprozess ( $!) abgebrochen. Sie stoppen Ihre Muschel.
  • In der 5. Version führen Sie stattdessen im Hintergrund aus YourCommandund speichern diese PID sofort in der Variablen $pid. Anschließend führen Sie im Hintergrund ein Nickerchen von 5 Minuten und den darauf folgenden Befehl aus, mit dem die gespeicherte PID gelöscht wird. 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 eine eventuelle Ausführung eines anderen Programms im Hintergrund aktualisiert werden kann. Mit einfachen Worten vermeiden Sie das Risiko , den falschen oder gar keinen Prozess zu beenden.
  • In der 6. Version heißt es eine neue Bash-Shell, die sich in 5 Minuten über selbst umbringt $$. 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 im Hintergrund gesendet wird. Führen Sie dann YourCommand im Vordergrund aus.

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

Verweise

  • [ 1 ] Die Coreutils
  • [ 2 ] Das Handbuch für Bash-Anfänger
  • [ 3 ] Die BashFAQ
Hastur
quelle
2
"Mit Schlaf kannst du deine Fantasie nutzen oder dich inspirieren lassen [Link zu Bash FAQ]" +1 #thatsenoughinternetfortoday
joeytwiddle
11

Für Ihren speziellen Fall, die meisten Implementierungen der pingUnterstützung -coder --countnach einer bestimmten Anzahl von Pings zu beenden:

ping -c 300 host.example.com

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

Toby Speight
quelle
7
Ich habe den Eindruck, dass OP nur pingfür ein konkretes Beispiel vorgesehen ist. Er möchte nicht für jedes Programm eine Einzellösung.
user1717828
8

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 $@:...: Die Positionsparameter ( $*, $@, "$*", "$@") 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 dies $0der 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}". Fügen Sie außerdem die Positionsparameter fast immer in doppelte Anführungszeichen ein.

MariusMatutiae
quelle
1
Ich würde das Skript wahrscheinlich so entwerfen, dass die Zeit als erstes oder letztes Argument verwendet wird und alle anderen Argumente als Befehl ausgeführt werden. Bash Word-Split zu lassen $1ist ziemlich grob. Sie könnten auch einfach sleep "$1"oder etwas in countdown.
Peter Cordes
1
@PeterCordes Gemacht nach Ihren Wünschen.
MariusMatutiae
Mit der Zeit in first arg können Sie dies tun time=$1; shiftund benötigen dann nicht die Array-Slicing-Syntax für die Positionsparameter. Aber ja, das ist viel einfacher.
Peter Cordes
1
@PeterCordes Einverstanden, aber Sie haben mich gefragt, ob ich einen sichereren Weg dazu kenne und ob ich nur faul oder einfach ignorant bin. lol.
MariusMatutiae
Als Poster, das speziell nach einem Programm gefragt wurde, das unterbrochen werden kann ctrl-c, ist es wahrscheinlich besser, es kill -INTstattdessen zu versuchen kill -9(oder es zumindest -9erst nach wenigen Sekunden zu versuchen, wenn das erste nicht erfolgreich war - es gibt dem Programm die Möglichkeit, sauber zu beenden und keine temporären Dateien zu hinterlassen usw.)
Matija Nalis
5

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

  • w deadline Geben Sie ein Timeout in Sekunden an, bevor Ping beendet wird, unabhängig davon, wie viele Pakete gesendet oder empfangen wurden. In diesem Fall stoppt der Ping- Vorgang nicht, nachdem die Anzahl der Pakete gesendet wurde. Er wartet entweder auf den Ablauf der Frist oder auf die Beantwortung der Anzahl der Tests oder auf 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

user2428118
quelle