67 votes

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

Existe-t-il un moyen simple de permettre à une commande spécifique (qui ne peut être interrompue qu'au moyen de la fonction Ctrl-C ) fonctionne automatiquement pendant 5 minutes ?

Par exemple :

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

ou toute autre commande qui ne se termine pas d'elle-même.

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

87voto

Gombai Sándor Points 3990

En fait, c'est ce que timeout est pour :

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

68voto

Toby Speight Points 4636

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

NOM

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

SYNOPSIS

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

y

NOM

timeout - exécuter une commande avec une limite de temps

SYNOPSIS

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

Ils sont conditionné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)       |
\-----------------------------+------------+----------------/

Notes :

  1. timeout utilise toujours SIGKILL comme signal de dernier recours.
  2. timeout n'a pas de fonctionnalité pour quitter avec un signal lorsque le programme enfant le fait.

L'état de sortie des deux programmes diffère, mais il est difficile de le résumer clairement, je vous suggère donc de consulter vous-même les pages du manuel pour cela.

Comme timeout est installé par défaut sur un plus grand nombre de systèmes ( coreutils est un paquetage standard dans de nombreuses distributions), je vous suggère de l'utiliser à moins que vous n'ayez besoin de la fonctionnalité supplémentaire fournie par timelimit .

17voto

Hastur Points 17791

Pure bash intégré, sans coreutils

J'ai constaté que cette solution fonctionne dans bash en s'appuyant sur un intégré sans appeler un exécutable externe. Il fonctionne sur des systèmes sur lesquels n'a pas été installé le logiciel de gestion de l'environnement. 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 avec & son PID est stocké dans la variable interne $! (présent dans la version moderne de dash , csh , bash , tcsh , zsh ...).
Ce qui fait vraiment la différence entre les coquilles, c'est la présence du intégré 命令 read [ 2 ] et de l'option -t . Dans la première version, si l'utilisateur ne complète pas une ligne d'entrée avant le nombre de secondes spécifié, l'instruction sera interrompue et un code de retour d'erreur sera généré.

-t TIMEOUT Provoque un délai de lecture et renvoie un échec si une ligne complète d'entrée n'est pas lue dans les secondes TIMEOUT.

La deuxième version fonctionne comme la première mais vous pouvez interrompre le délai d'exécution en appuyant simplement sur enter .
En effet, l'opérateur ou || exécute le kill uniquement si le read se termine avec un code de retour différent de zéro, comme lorsque le délai d'attente est expiré. Si vous appuyez sur enter avant ce moment, il retournera 0 et il ne tuera pas votre commande précédente.


Solutions Coreutils [ 1 ]

Quand coreutils sont présents sur votre système et vous n'avez pas besoin d'économiser le temps et les ressources pour appeler un programme externe, timeout y sleep et sont tous deux des moyens parfaits pour atteindre votre objectif.

timeout L'utilisation de timeout est simple.
Eventuellement, vous pouvez envisager d'utiliser aussi le -k pour envoyer un signal kill supplémentaire si le premier échoue.

timeout 5m YourCommand                                         # 3rd version 

sleep Avec sleep vous pouvez utiliser votre imagination ou prendre des inspirations [ 3 ] . Notez que vous pouvez laisser votre commande en arrière-plan ou en avant-plan (par ex. top doit 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

Explications

  • Dans la 4ème version, vous exécutez en arrière-plan YourCommand puis votre Shell sleep s pendant 5 minutes. Lorsqu'il sera terminé, le dernier processus d'arrière-plan ( $! ) seront tués. Vous arrêtez votre Shell.
  • Dans la 5e version, vous exécutez plutôt en arrière-plan YourCommand et vous stockez immédiatement ce PID dans la variable $pid . Ensuite, vous exécutez en arrière-plan un sieste de 5 minutes et sa commande conséquente qui tuera ce PID stocké. Comme vous avez envoyé ce groupe de commandes en arrière-plan, vous n'arrêtez pas votre Shell. Vous avez besoin de stocker le PID dans une variable parce que la valeur de $! peut être mis à 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 bash Shell qui se suicidera dans 5 minutes via $$ alors c'est votre commande qui est exécutée et qui reste au premier plan.
  • Dans la 7ème version, il est invoqué un sous-shell () qui stocke son PID dans une variable ( cmdpid ) et se tue avec un autre sous-shell envoyé en exécution d'arrière-plan, puis lancez VotreCommande en avant-plan.

Bien sûr, dans chaque version, vous pouvez envoyer le signal de mise à mort dont vous avez besoin, du signal par défaut au signal de mise à mort. extrême kill -9 à n'utiliser que lorsque cela est vraiment nécessaire.

Références

  • [ 1 Les Coreutils
  • [ 2 Le guide du débutant Bash
  • [ 3 ] Le BashFAQ

11voto

Toby Speight Points 4636

Pour votre cas particulier, la plupart des implémentations de ping soutien -c o --count pour se 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.

8voto

MariusMatutiae Points 45233

Vous pouvez le faire avec un simple script comme celui-ci :

#!/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é selon 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 : de tous les paramètres, prendre COUNT, le premier à être pris étant celui de la position START ; si COUNT est omis, prendre tous les paramètres jusqu'à la fin, en commençant par la position START. Rappelons que $0 est le nom du programme. Si START est négatif, commencez à compter à partir de la fin, et rappelez-vous que COUNT ne peut pas être négatif, donc le dernier argument est "${@:-1}" . Aussi, à peu près toujours inclure les paramètres positionnels entre guillemets.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X