Quel est un moyen simple de laisser une commande s'exécuter pendant 5 minutes? [dupliquer]

66

Existe-t-il un moyen simple de laisser une commande spécifique (uniquement terminable Ctrl-C) exécutée automatiquement pendant 5 minutes?

Par exemple:

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

ou toute autre commande qui ne se termine pas.

J'aimerais pouvoir spécifier une limite de temps, pas seulement 5 minutes.

Eckhart
la source

Réponses:

67

Il y a (au moins) deux programmes qui fournissent cette fonctionnalité:

NOM

timelimit - limiter efficacement le temps absolu d'exécution d'un processus

SYNOPSIS

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

et

NOM

timeout - lancer une commande avec une limite de temps

SYNOPSIS

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

Ils sont emballés comme suit:

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

Comparaison:

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

Remarques:

  1. timeoututilise toujours SIGKILLcomme signal de dernier recours.
  2. timeout n'a aucune fonctionnalité pour sortir avec un signal lorsque le programme enfant le fait.

Les états de sortie des deux programmes diffèrent, mais il est difficile de les résumer soigneusement. Je vous suggère donc de consulter les pages du manuel vous-même.

Comme il timeoutest installé sur plusieurs systèmes par défaut ( coreutilsest un paquet standard dans de nombreuses distributions), je vous suggère de l’utiliser sauf si vous avez besoin des fonctionnalités supplémentaires fournies par timelimit.

Toby Speight
la source
10
Pourquoi voudriez-vous utiliser l'un plutôt que l'autre?
Brice M. Dempsey
2
@ BriceM.Dempsey Sur mon ordinateur local, le délai d'attente est présent, mais le délai n'est pas respecté (bien qu'il soit disponible dans le référentiel). Donc, si l’un d’entre eux est pré-installé ... En dehors de cela, en regardant les signatures de méthode, je peux voir qu’elles font différentes choses et ont différents cas d’utilisation.
Benubird
Notez qu'il existe au moins deux implémentations de timelimit. Voir Comment puis-je tuer un processus et m'assurer que le PID n'a pas été réutilisé pour plus d'informations sur eux et le délai d'expiration GNU.
sch
1
@ BriceM.Dempsey timeoutest inclus dans GNU coreutils , timelimitn’est pas. Vous pouvez avoir installé aucun, un ou les deux. Pour la seconde, il est signalé que timelimit exécute une commande et termine le processus généré après un temps donné avec un signal donné. Un signal "warning" est envoyé en premier , puis, après un délai d'attente, un signal "kill", similaire à la façon dont init (8) fonctionne à l'arrêt. Donc, même un comportement différent dans le milieu .
Hastur
Puisque GNU coreutils est préinstallé sur chaque système GNU / Linux, timeoutc’est la voie à suivre.
rexkogitans
87

En fait, c’est pour ça que timeout:

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
la source
16

Pure bashconstruit, sans coreutils

J'ai trouvé que cette solution fonctionne en bashs'appuyant sur une commande intégrée sans appeler un exécutable externe. Cela fonctionne sur le système où finalement ne sont même pas installés les coreutils [ 1 ]

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

Explications : comme d' habitude lorsque vous envoyez une commande en arrière - plan &, son PID est stocké dans la variable interne $!(présent dans la version moderne dash, csh, bash, tcsh, zsh...).
Ce qui fait vraiment la différence entre les obus est la présence de la commande intégrée read[ 2 ] et de l’option -t. Dans la 1ère version, si l'utilisateur ne complète pas une ligne d'entrée avant le nombre de secondes spécifié, l'instruction est terminée et un code de retour d'erreur est généré.

-t TIMEOUT Cause la lecture pour expirer et renvoyer l'échec si une ligne complète d'entrée n'est pas lue dans les délais TIMEOUT.

La deuxième version fonctionne comme la 1ère mais vous pouvez abandonner le délai de mise à mort en appuyant simplement sur enter.
En effet, l'opérateur ou ||n'exécute l' killinstruction que si la readcommande se termine avec un code retour différent de zéro, par exemple lorsque le délai d'attente a expiré. Si vous appuyez enteravant ce moment, il renverra 0 et il ne tuera pas votre commande précédente.


Solutions Coreutils [ 1 ]

Lorsque coreutils sont présents sur votre système et vous avez pas besoin d'économiser le temps et les ressources nécessaires pour appeler un programme externe, timeoutet sleepet sont les deux moyens parfaits pour atteindre votre objectif.

timeoutL'utilisation de timeoutest simple.
En fin de compte, vous pouvez également utiliser l' -koption permettant d'envoyer un signal de neutralisation supplémentaire si le premier échoue.

timeout 5m YourCommand                                         # 3rd version 

sleep Avec sleepvous pouvez utiliser votre fantaisie ou prendre des inspirations [ 3 ] . Notez que vous pouvez laisser votre commande en arrière-plan ou au premier plan (par exemple, il topdoit généralement être au premier plan).

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

Des explications

  • Dans la 4ème version, vous exécutez en tâche de fond YourCommandvotre shell sleeppendant 5 minutes. Quand il sera fini, le dernier processus d'arrière-plan ( $!) sera tué. Vous arrêtez votre coquille.
  • Dans la 5ème version, vous exécutez plutôt en arrière YourCommand- plan et vous stockez immédiatement ce PID dans la variable $pid. Ensuite, vous exécutez en arrière-plan une sieste de 5 minutes et la commande qui en découle qui va tuer ce PID stocké. Comme vous avez envoyé ce groupe de commandes en arrière-plan, vous n'arrêtez pas votre shell. Vous devez stocker le PID dans une variable, car la valeur de $!peut être mise à jour par l'exécution éventuelle d'un autre programme en arrière-plan. En termes simples, vous évitez le risque de tuer le mauvais processus ou aucun processus du tout.
  • Dans la 6ème version, il s’agit d’un nouveau shell bash qui se suicidera dans 5 minutes via $$, puis il exécutera votre commande qui reste au premier plan.
  • Dans la 7ème version, il est appelé un sous ()- shell qui stocke son PID dans une variable ( cmdpid) et se détruit avec un autre sous-shell envoyé en exécution en arrière-plan, puis lance votre commande au premier plan.

Bien sûr, dans chaque version, vous pouvez envoyer le signal de suppression dont vous avez besoin, de la valeur par défaut à l’ extrême kill -9 , pour n’être utilisé que lorsque vous en avez vraiment besoin.

Références

  • [ 1 ] Les Coreutils
  • [ 2 ] Le Guide du débutant Bash
  • [ 3 ] Le BashFAQ
Hastur
la source
2
« Avec le sommeil , vous pouvez utiliser votre fantaisie ou prendre quelques inspirations [lien vers Bash FAQ] » +1 #thatsenoughinternetfortoday
joeytwiddle
11

Pour votre cas particulier, la plupart des implémentations de pingsupport -cou --countà terminer après un nombre particulier de pings:

ping -c 300 host.example.com

Pour une solution plus générale, voir les autres réponses.

Toby Speight
la source
7
J'ai l'impression que OP vient de fournir pingun exemple concret. Il ne veut pas de solution au cas par cas pour chaque programme.
user1717828
8

Vous pouvez le faire avec un script simple comme ceci:

#!/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 utilisé conformément à la suggestion de Matija Nalis dans le commentaire ci-dessous).

Une explication de l'expression bash (peu commune?) $@:...: Les paramètres de position, ( $*, $@, "$*", "$@") admettent la spécification supplémentaire suivante, par exemple:

"${@:START:COUNT}"

ce qui signifie: parmi tous les paramètres, prenez-les en COMPTE, le premier à prendre est celui à la position START; si COUNT est omis, prenez-les tous jusqu'à la fin, en commençant par la position START. Rappelez-vous que $0c'est le nom du programme. Si START est négatif, commencez à compter à partir de la fin et souvenez-vous que COUNT ne peut pas être négatif, d'où le dernier argument "${@:-1}". En outre, vous devez toujours inclure les paramètres de position entre guillemets doubles.

MariusMatutiae
la source
1
Je concevrais probablement le script pour prendre le temps comme premier ou dernier argument et exécuter tous les autres arguments comme commande. Laisser bash diviser les mots $1est assez grossier. En outre, vous pouvez simplement sleep "$1"ou quelque chose dans countdown.
Peter Cordes
1
@PeterCordes Fait, selon vos souhaits.
MariusMatutiae
Le temps en premier argument vous permet de le faire time=$1; shift, et vous n'avez alors pas besoin de la syntaxe de découpage en tableau pour les paramètres de position. Mais oui, c'est beaucoup plus simple.
Peter Cordes
1
@PeterCordes D'accord, mais vous m'avez demandé de voir si je connaissais un moyen plus sûr de le faire et que je venais d'être paresseux, ou si j'étais tout simplement ignorant. lol.
MariusMatutiae
en tant que poster spécifiquement interrogé sur le programme qui peut être interrompu ctrl-c, il est probablement préférable d'essayer kill -INTau lieu de kill -9(ou du moins d'essayer -9seulement après quelques secondes si le premier n'a pas abouti - cela donne au programme une chance de quitter proprement et de ne pas laisser de fichiers temporaires etc autour de)
Matija Nalis
5

Puisque vous mentionnez pingdans votre exemple; cette commande a quelques options pour arrêter après un laps de temps spécifique:

  • w delay Spécifiez un délai d'expiration, en secondes, avant la fin du ping, quel que soit le nombre de paquets envoyés ou reçus. Dans ce cas, le ping ne s’arrête pas après l’ envoi du nombre de paquets, il attend l’ expiration de la date d’ expiration ou jusqu’à ce que le nombre de sondes de décompte soit résolu, ou une notification d’erreur du réseau.
  • W timeout Temps d'attente en réponse, en secondes. L'option n'affecte que le délai d'attente en l'absence de réponse, sinon ping attend deux RTT.

-man ping

utilisateur2428118
la source