Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Interrompre une commande si elle dure plus de N secondes dans un script (bash a priori)

30 réponses
Avatar
Francois Lafont
Bonjour à tous,

J'explique un peu le contexte d'abord. J'ai un script local qui est
lancé à l'ouverture de session sur une Debian Squeeze et dans ce script
local il y a ça :

#-------------------------------------------
if [ -r "/mnt/script_distant" ]; then
/bin/bash "/mnt/script_distant"
fi
#-------------------------------------------

Je teste si le fichier script_distant est bien accessible en lecture car
en réalité /mnt est un répertoire sur lequel est monté un partage Samba
et il se peut que le serveur Samba soit (momentanément) en carafe et
donc, bien que le montage ait été effectué correctement auparavant, le
fichier script_distant peut être (momentanément) inaccessible.

Mon problème, c'est que ce test dure vraiment longtemps dans le cas où
justement le serveur est en carafe (ça peut prendre une vingtaine de
secondes parfois) ce qui ralentit beaucoup trop l'ouverture de session.
Ce que je voudrais, du coup, c'est interrompre le test s'il dure plus de
5 secondes (par exemple), sachant qu'au delà de cette limite 5 secondes,
je décide que c'est mort pour le lancement du script_distant et le
script local passe à la suite de son travail.

Donc ma question est : comment faire pour interrompre une commande si
elle dure plus de 5 secondes ?

En faisant des recherches sur le Web, je suis arrivé à ça :

#-------------------------------------------
# Exemple fictif de commande qui peut durer...
sleep 10 &

compteur=$((1))

COMMANDE_INTERROMPUE=false

# On teste si le processus est en cours
# avec la valeur de retour de « ps $! ».

while ps $! >/dev/null 2>&1; do

if [ $compteur -le 5 ]; then
sleep 1
compteur=$((compteur+1))
else
kill -SIGKILL $! >/dev/null 2>&1
COMMANDE_INTERROMPUE=true
#break
fi

done

if $COMMANDE_INTERROMPUE; then
echo "La commande a été interrompue"
else
echo "La commande n'a pas été interrompue"
fi
#-------------------------------------------

1) Est-ce correct d'après vous ? Toute remarque constructive est la
bienvenue. ;-)

2) Je me pose une question à propos du « break » que j'ai laissé en
commentaire ci-dessus. En l'état, si je lance ce script (il s'appelle
test.bash), j'ai :

#-------------------------------------------
$ bash test.bash
test.bash: line 22: 10160 Processus arrêté sleep 10
La commande a été interrompue
#-------------------------------------------

Je n'arrive pas à comprendre pourquoi j'ai la sortie « test.bash: line
22: 10160 Processus arrêté sleep 10 » ? Elle provient de la sortie
standard des erreurs du script test.bash lui-même, c'est donc une erreur
dans le script, mais je ne la comprends pas. En revanche, si je «
décommente » le break, alors :

#-------------------------------------------
$ bash test.bash
La commande a été interrompue
#-------------------------------------------

Je n'ai plus cette erreur. Avez-vous une explication ?

Merci d'avance pour votre aide.


--
François Lafont

10 réponses

1 2 3
Avatar
Francois Lafont
Le 02/03/2012 18:46, Fabien LE LEZ a écrit :

"/mnt/script_distant"



À quoi ressemble ce script ? Généralement, dans un programme de
connexion réseau, on peut mettre un timeout.



Il est trop long et moche pour que je le poste ici. :-)
Mais en gros, il copie/efface (ou pas) certains fichiers pas bien gros
dans le /home de l'utilisateur qui se connecte.

Mais ce script_distant, lui, n'est pas long à l'exécution. Vraiment. Ce
qui est long c'est le test [ -r "/mnt/script_distant" ] *si et seulement
si* le serveur est en carafe.

Si tout va bien le test et l'exécution de script_distant sont très
rapides, vraiment aucun souci de ce côté là. En revanche si le serveur
est HS (ce que je peux simuler par exemple avec un petit «
/etc/init.d/samba stop » sur le serveur qui est une Debian Lenny), alors
l'exécution du test peut durer entre 10 et 20 secondes.

--
François Lafont
Avatar
Arnaud Gomes-do-Vale
Francois Lafont writes:

Donc ma question est : comment faire pour interrompre une commande si
elle dure plus de 5 secondes ?



Avec timeout, tout simplement. :-)

:~% time timeout 5s sleep 20
timeout 5s sleep 20 0.00s user 0.00s system 0% cpu 5.008 total
:~% rpm -qf =timeout
coreutils-8.10-2.fc15.x86_64

--
Arnaud
http://blogs.glou.org/arnaud/
Avatar
Philippe Naudin
Le ven 02 mar 2012 19:39:32 CET, Francois Lafont a écrit:

Au passage, si quelqu'un a une explication sur l'erreur en question dans
le code de mon premier message, ça m'intéresse. Fabien Le Lez a donn é
une explication mais je reste perplexe.



Cette erreur n'est pas une erreur. C'est une info :

$ sleep 15 &
[1] 31921

$ kill $!
[1]+ Complété sleep 15

$ sleep 15 &
[1] 31925

$ kill -SIGKILL $!
[1]+ Processus arrêté sleep 15


--
Philippe Naudin
Avatar
Francois Lafont
Le 02/03/2012 19:53, Arnaud Gomes-do-Vale a écrit :

Donc ma question est : comment faire pour interrompre une commande si
elle dure plus de 5 secondes ?



Avec timeout, tout simplement. :-)



Jusque là, j'ignorais l'existence de cette commande. C'est exactement ce
qu'il me faut en effet. :-)

:~% time timeout 5s sleep 20
timeout 5s sleep 20 0.00s user 0.00s system 0% cpu 5.008 total
:~% rpm -qf =timeout
coreutils-8.10-2.fc15.x86_64



Génial, merci bien Arnaud !

En plus, timeout a le bon goût de renvoyer la valeur 124 si le délai est
dépassé et la valeur de retour de la commande en argument sinon. Du
coup, je vais pouvoir faire un truc comme ça par exemple :

#-----------------------------------------
timeout --signal SIGTERM 5s test -r "/mnt/script_distant"

if [ "$?" = 0 ]; then
echo "Test Ok (et il n'a pas été interrompu)."
else
echo "Problème."
fi
#-----------------------------------------


--
François Lafont
Avatar
Philippe Naudin
Le ven 02 mar 2012 21:20:46 CET, Francois Lafont a écrit:

Le 02/03/2012 19:57, Philippe Naudin a écrit :

>> Au passage, si quelqu'un a une explication sur l'erreur en question da ns
>> le code de mon premier message, ça m'intéresse. Fabien Le Lez a do nné
>> une explication mais je reste perplexe.
>
> Cette erreur n'est pas une erreur. C'est une info :

Ok mais elle provient bien de la sortie des erreurs.



De stderr :)
Il y a plein de programmes qui affichent des informations sur stderr,
afin de ne pas perturber stdout. Si ce n'était pas le cas, les
opérations du genre
programme1 | programme2
seraient à s'arracher les cheveux. Les informations en question ne sont
pas toutes des messages d'erreurs.

> $ sleep 15 &
> [1] 31921
>
> $ kill $!
> [1]+ Complété sleep 15
>
> $ sleep 15 &
> [1] 31925
>
> $ kill -SIGKILL $!
> [1]+ Processus arrêté sleep 15

Ok, mais dans ce cas, comment expliques-tu que le message n'apparaisse
pas lorsqu'on « décommente » le break ?



Chez moi, le message "Processus arrêté" est affiché avec ou sans brea k.

Je suppose que ce qui se passe chez toi, c'est que le kill met un
certain temps à s'exécuter. Avec le break, "Processus arrêté"
s'affiche sur un stderr qui a été fermé ("bash test.bash" est déjà
terminé), et tu ne vois rien.

Pour vérifier : décommente le break mais ajoute un sleep 1 à la fin de
test.bash. Le message de kill doit s'afficher.

--
Philippe Naudin
Avatar
Benoit Izac
Bonjour,

le 02/03/2012 à 15:52, Francois Lafont a écrit dans le message
<4f50deb8$0$451$ :

#-------------------------------------------
# Exemple fictif de commande qui peut durer...
sleep 10 &

compteur=$((1))



compteur=1

COMMANDE_INTERROMPUEúlse

# On teste si le processus est en cours
# avec la valeur de retour de « ps $! ».

while ps $! >/dev/null 2>&1; do

if [ $compteur -le 5 ]; then
sleep 1
compteur=$((compteur+1))
else
kill -SIGKILL $! >/dev/null 2>&1



À moins d'avoir une bonne raison, on utilise plutôt « -SIGTERM ».

COMMANDE_INTERROMPUE=true
#break
fi

done

if $COMMANDE_INTERROMPUE; then
echo "La commande a été interrompue"
else
echo "La commande n'a pas été interrompue"
fi
#-------------------------------------------

1) Est-ce correct d'après vous ? Toute remarque constructive est la
bienvenue. ;-)



Oui.

2) Je me pose une question à propos du « break » que j'ai laissé en
commentaire ci-dessus. En l'état, si je lance ce script (il s'appelle
test.bash), j'ai :

#-------------------------------------------
$ bash test.bash
test.bash: line 22: 10160 Processus arrêté sleep 10
La commande a été interrompue
#-------------------------------------------

Je n'arrive pas à comprendre pourquoi j'ai la sortie « test.bash: line
22: 10160 Processus arrêté sleep 10 » ? Elle provient de la sortie
standard des erreurs du script test.bash lui-même, c'est donc une erreur
dans le script, mais je ne la comprends pas. En revanche, si je «
décommente » le break, alors :

#-------------------------------------------
$ bash test.bash
La commande a été interrompue
#-------------------------------------------
Je n'ai plus cette erreur. Avez-vous une explication ?



Je n'ai pas ce comportement (bash-4.2.20). Dans les deux cas j'ai le
message mais pas à la même ligne :

% bash test/test.bash
test/test.bash: line 23: 1106 Killed sleep 10
La commande a été interrompue
% bash test/test.bash
La commande a été interrompue
test/test.bash: line 29: 1115 Killed sleep 10

Et ça me parait logique car dans un cas, tu fais un ps qui échoue avant
de sortir, dans l'autre, tu sors immédiatement du while. Sinon, le
message vient de bash qui indique juste qu'un des processus qu'il
a lancé en arrière plan vient d'être tué. Tu peux utiliser le buitin
« disown » pour ne plus avoir ce message.

--
Benoit Izac
Avatar
Tonton Th
On 03/02/2012 04:10 PM, Francois Lafont wrote:

#-----------------------------------------
$ ps -a
PID TTY TIME CMD
10279 pts/1 00:00:00 sleep
10283 pts/0 00:00:00 ps

$ kill -SIGINT 10279; ps 10279
PID TTY STAT TIME COMMAND

$
#-----------------------------------------

J'ai bien détruit le processus 10279 puis j'ai fait un ps sur ce
processus et pourtant je n'ai pas le message d'erreur.




:~$ sleep 666 &
[1] 10337
:~$ ps aux | grep 666
tth 10337 0.0 0.0 3236 624 pts/3 S 21:55 0:00 sleep 666

:~$ kill -0 10337
:~$ echo $?
0
:~$ kill -9 10337
[1]+ Killed sleep 666
:~$ kill -0 10337
bash: kill: (10337) - No such process
:~$ echo $?
1
:~$

--

Nous vivons dans un monde étrange/
http://foo.bar.quux.over-blog.com/
Avatar
Francois Lafont
Bonsoir,

Je réponds un peu tardivement à ce message car apparemment news.free.fr
a eu des petits soucis... (Si vous connaissez un autre serveur de news
gratuit etc., ça m'intéresse.)

Le 03/03/2012 21:12, Benoit Izac a écrit :

le 02/03/2012 à 15:52, Francois Lafont a écrit dans le message
<4f50deb8$0$451$ :

#-------------------------------------------
# Exemple fictif de commande qui peut durer...
sleep 10 &

compteur=$((1))



compteur=1



Y a-t-il une réelle différence au final entre les 3 instructions
ci-dessous ?

1) c=1
2) c="1"
3) c=$((1))


COMMANDE_INTERROMPUEúlse

# On teste si le processus est en cours
# avec la valeur de retour de « ps $! ».

while ps $! >/dev/null 2>&1; do

if [ $compteur -le 5 ]; then
sleep 1
compteur=$((compteur+1))
else
kill -SIGKILL $! >/dev/null 2>&1



À moins d'avoir une bonne raison, on utilise plutôt « -SIGTERM ».



Ok, merci.

2) Je me pose une question à propos du « break » que j'ai laissé en
commentaire ci-dessus. En l'état, si je lance ce script (il s'appelle
test.bash), j'ai :

#-------------------------------------------
$ bash test.bash
test.bash: line 22: 10160 Processus arrêté sleep 10
La commande a été interrompue
#-------------------------------------------

Je n'arrive pas à comprendre pourquoi j'ai la sortie « test.bash: line
22: 10160 Processus arrêté sleep 10 » ? Elle provient de la sortie
standard des erreurs du script test.bash lui-même, c'est donc une erreur
dans le script, mais je ne la comprends pas. En revanche, si je «
décommente » le break, alors :

#-------------------------------------------
$ bash test.bash
La commande a été interrompue
#-------------------------------------------
Je n'ai plus cette erreur. Avez-vous une explication ?



Je n'ai pas ce comportement (bash-4.2.20).



Moi, c'est la version 4.1.5(1)-release (x86_64-pc-linux-gnu).

Dans les deux cas j'ai le
message mais pas à la même ligne :

% bash test/test.bash
test/test.bash: line 23: 1106 Killed sleep 10
La commande a été interrompue
% bash test/test.bash
La commande a été interrompue
test/test.bash: line 29: 1115 Killed sleep 10

Et ça me parait logique car dans un cas, tu fais un ps qui échoue avant
de sortir, dans l'autre, tu sors immédiatement du while. Sinon, le
message vient de bash qui indique juste qu'un des processus qu'il
a lancé en arrière plan vient d'être tué. Tu peux utiliser le buitin
« disown » pour ne plus avoir ce message.



Ok, merci bien pour cette précision.


--
François Lafont
Avatar
Luc.Habert.00__arjf
Francois Lafont :

Y a-t-il une réelle différence au final entre les 3 instructions
ci-dessous ?

1) c=1
2) c="1"



Ces deux-là ne diffèrent qu'au niveau du lexing, l'arbre syntaxique
pondu doit être identique.

3) c=$((1))



Là, ça va donner le même résultat sur ce cas particulier, mais l'arbre
syntaxique (et l'exécution qui en découle sauf optimisation à la noix) est
vraiment différent : ton 1 est converti en nombre, ce nombre devient
immédiatement le résultat de l'expression, et est reconverti en string à la
fin. Tu peux voir la différence avec « $((01)) », ça donne « 1 ».
Avatar
Fabien LE LEZ
On Wed, 07 Mar 2012 22:00:04 +0100, Francois Lafont
:

(Si vous connaissez un autre serveur de news gratuit etc., ça m'intéresse.)



À défaut de gratuit, tu peux essayer Astraweb :
http://www.news.astraweb.com/plans.html

Il ont une offre "25 Go pour $10". Si tu ne télécharges pas de
binaires, les 25 Go devrait te suffire pour un paquet d'années.

Cela dit, la panne de ce week-end est la première depuis très
longtemps. Le serveur news.free.fr est, d'une manière générale, très
stable.
1 2 3