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

Timer max pour un process

6 réponses
Avatar
Kevin Denis
Bonjour,

j'ai un fichier correspondant à une liste de tache à faire.
Certaines peuvent prendre un temps indeterminé (long); je souhaite
arrêter ce traitement au bout d'un certain temps.

Le script original est le suivant:

_job()
{ (des trucs..) }

for tache in `cat liste_tache`
do
echo la tache $tache est lancée
_job $tache
done

Maintenant, je souhait forcer un timeout de 5s par tache (le timeout
est à la louche, la précision temporelle n'est pas recherchée). Je
cherche juste à éviter certains timeout monstrueux. En gros, soit la
tache réussit en moins de 1 à 2s, soit elle est bloquée pour plusieurs
minutes; de plus tuer la tache est sans conséquence dans mon cas.

J'ai donc écrit:
for tache in `cat liste_tache`
do
echo la tache $tache est lancée
_job $tache & job_pid=$!
( sleep 5; echo la tache $tache a un PB ; kill $job_pid ) & ruler_pid=$!
wait $job_pid
kill $ruler_pid
done

J'ai deux questions:
1/ Ma sortie est parasitée par tous les kill envoyés (j'ai beau rediriger
la sortie standard ou la sortie d'erreur vers /dev/null, j'ai toujours
le message de kill m'indiquant que le process est tué). Comment afficher
une sortie propre?

2/ Est-ce correct ou bien y a t'il plus propre?

Merci
--
Kevin

6 réponses

Avatar
Cyrille Lefevre
Kevin Denis a écrit :
J'ai donc écrit:
for tache in `cat liste_tache`
do
echo la tache $tache est lancée
_job $tache & job_pid=$!
( sleep 5; echo la tache $tache a un PB ; kill $job_pid ) & ruler_pid= $!
wait $job_pid
kill $ruler_pid
done

J'ai deux questions:
1/ Ma sortie est parasitée par tous les kill envoyés (j'ai beau red iriger
la sortie standard ou la sortie d'erreur vers /dev/null, j'ai toujours
le message de kill m'indiquant que le process est tué). Comment affic her
une sortie propre?

2/ Est-ce correct ou bien y a t'il plus propre?

Merci




Bonjour,

je suppose que tu es sous bash ?
mauvais shell, changer shell...

1/
[[ -n ${BASH_VERSION} ]] && exec 9>&2 2> /dev/null
kill $ruler_pid
[[ -n ${BASH_VERSION} ]] && exec 2>&9 9>&-

idem pour le kill $job_pid je supppose...

cela semble correcte hormis la boucle for, j'ai toujours
une préférence pour les boucles while dans ce cas :

while read -r REPLY; do
...
done < liste_tache

ce qui évite, par ailleurs, un fork inutile :-)

PS : normalement, il n'est pas nécessaire de spécifier un
paramètre à read, dans ce cas il est supposé remplir la
variable REPLY. pour autant, je suis tombé sur un cas, en
bash, ou REPLY n'était pas correctement rempli (ou vidé
s'il n'y a rien à lire, je ne sais plus)...

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
Avatar
Kevin Denis
Le 20-05-2009, Cyrille Lefevre a écrit :
J'ai deux questions:
1/ Ma sortie est parasitée par tous les kill envoyés (j'ai beau rediriger
la sortie standard ou la sortie d'erreur vers /dev/null, j'ai toujours
le message de kill m'indiquant que le process est tué). Comment afficher
une sortie propre?

2/ Est-ce correct ou bien y a t'il plus propre?



je suppose que tu es sous bash ?



Oui, système linux, shell par défaut (donc bash)

mauvais shell, changer shell...

1/
[[ -n ${BASH_VERSION} ]] && exec 9>&2 2> /dev/null
kill $ruler_pid
[[ -n ${BASH_VERSION} ]] && exec 2>&9 9>&-

idem pour le kill $job_pid je supppose...



Toujours pas. La sortie est toujours parasitée par les messages
line 15: 8871 Complété job -q $tache
line 16: kill: (8872) - Aucun processus de ce type
Etc..

Mais j'ai compris pourquoi. En fait ce n'est pas un output du script
mais un output du shell qui lance le script. Ainsi lancer le script:
script > resultat
(...)
cat resultat

donne un resultat propre (ie, sans les messages kill)

La solution consiste donc à lancer un sous-shell qui va lui, tout
envoyer vers /dev/null, évitant de pourrir ma sortie standard.
Le problème, c'est que dans ce sous shell, un echo "..." n'est
pas affiché. J'ai du donc employer une fonction, et un fichier
temporaire:

_func_do()
{
#clean_up
[ -f result ] && rm result
touch working
for tache in `cat liste_tache`
do
echo $tache " en cours" >> result
_job $tache & tache_pid=$!
( sleep 3; kill $tache_pid ; echo PB $tache >> result ) & ruler_pid=$!
wait $tache_pid
kill $ruler_pid
done
#job done, on supprime le fichier working
rm working
}

#on lance cette fonction en tache de fond en renvoyant tout vers
#le /dev/null
( exec 9>&2 2> /dev/null
touch working
_func_do > /dev/null
exec 2>&9 9>&- ) &

#On affiche à l'écran ce qui se passe
while [ -f working ]
do
[ -f result ] && cat result
[ -f result ] && rm result
sleep 1
done
[ -f result ] && cat result
[ -f result ] && rm result

while read -r REPLY; do
...
done < liste_tache
ce qui évite, par ailleurs, un fork inutile :-)



Certes, le for était déjà présent, en fait. Je travaille à une
amélioration de script. L'idée, c'est qu'en connaissant le nombre de
tache, on soit capable d'estimer la limite haute du temps nécessaire à
les réaliser.
Je ne pensais pas que ce soit si tordu de mettre un timer,
en conservant une sortie lisible. Il n'existe pas de fonction shell
'toute intégrée' ? Genre:
timer -n 15s job
qui défnirait un max de 15s pour lancer et terminer une tache?

PS : normalement, il n'est pas nécessaire de spécifier un
paramètre à read, dans ce cas il est supposé remplir la
variable REPLY. pour autant, je suis tombé sur un cas, en
bash, ou REPLY n'était pas correctement rempli (ou vidé
s'il n'y a rien à lire, je ne sais plus)...



Ok, je vais voir. Je pense toutefois que je peux améliorer encore
un peu ce système, comme par exemple mettre une FIFO à la place
d'un fichier temporaire 'result' pour afficher la sortie.
--
Kevin
Avatar
Cyrille Lefevre
Kevin Denis a écrit :
Le 20-05-2009, Cyrille Lefevre a écrit :
1/
[[ -n ${BASH_VERSION} ]] && exec 9>&2 2> /dev/null
kill $ruler_pid
[[ -n ${BASH_VERSION} ]] && exec 2>&9 9>&-

idem pour le kill $job_pid je supppose...



Toujours pas. La sortie est toujours parasitée par les messages
line 15: 8871 Complété job -q $tache
line 16: kill: (8872) - Aucun processus de ce type
Etc..



tiens, ça marche d'habitude ! je retesterai à l'occasion, mais je sais
que j'utilise ce subterfuge dans des scripts existants et en prod...

Mais j'ai compris pourquoi. En fait ce n'est pas un output du script
mais un output du shell qui lance le script. Ainsi lancer le script:
script > resultat
(...)
cat resultat

donne un resultat propre (ie, sans les messages kill)

La solution consiste donc à lancer un sous-shell qui va lui, tout
envoyer vers /dev/null, évitant de pourrir ma sortie standard.
Le problème, c'est que dans ce sous shell, un echo "..." n'est
pas affiché. J'ai du donc employer une fonction, et un fichier
temporaire:



duplique stdout et envoie tes messages dedans, cf plus bas.

[snip]

#on lance cette fonction en tache de fond en renvoyant tout vers
#le /dev/null
( exec 9>&2 2> /dev/null
touch working
_func_do > /dev/null
exec 2>&9 9>&- ) &



(
echo to devnull
echo >&8 to stdout
echo >&9 to stderr
) 8>&1 9>&2 > /dev/null 2>&1

[snip]

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
Avatar
Lucas Levrel
Le 20 mai 2009, Kevin Denis a écrit :
Toujours pas. La sortie est toujours parasitée par les messages
line 15: 8871 Complété job -q $tache
line 16: kill: (8872) - Aucun processus de ce type



Je ne suis pas un expert, donc attention, ce qui suit est peut-être une
grosse connerie :-p

Déjà, l'erreur sur le deuxième kill est facile à enlever (grosse ruse !) :
( sleep 5s ; echo blabla ; kill $job_pid ; sleep 1s ) &

Et pour le wait, pourquoi pas :
wait $job_pid &>/dev/null
? J'ai fait un test avec un sleep comme tâche, ça marche...

--
LL
Avatar
Kevin Denis
Le 20-05-2009, Lucas Levrel a écrit :
Toujours pas. La sortie est toujours parasitée par les messages
line 15: 8871 Complété job -q $tache
line 16: kill: (8872) - Aucun processus de ce type



Je ne suis pas un expert, donc attention, ce qui suit est peut-être une
grosse connerie :-p

Déjà, l'erreur sur le deuxième kill est facile à enlever (grosse ruse !) :
( sleep 5s ; echo blabla ; kill $job_pid ; sleep 1s ) &



Ok.

Et pour le wait, pourquoi pas :
wait $job_pid &>/dev/null
? J'ai fait un test avec un sleep comme tâche, ça marche...



C'est curieux. Mais comme la solution donnée plus haut fonctionne bien,
je vais laisser tel quel :)
--
Kevin
Avatar
Kevin Denis
Le 20-05-2009, Cyrille Lefevre a écrit :
La solution consiste donc à lancer un sous-shell qui va lui, tout
envoyer vers /dev/null, évitant de pourrir ma sortie standard.
Le problème, c'est que dans ce sous shell, un echo "..." n'est
pas affiché. J'ai du donc employer une fonction, et un fichier
temporaire:



duplique stdout et envoie tes messages dedans, cf plus bas.



Finalement, un fifo est très pratique. Je crée le fifo, je dumpe
tout dans /dev/null sauf certains messages que je peux envoyer dans
ce fifo.
Ensuite, une boucle lit ce fifo et affiche en temps réél ce qui se
passe.

Merci
--
Kevin