Script Bash pour démarrer le processus, attendre au hasard, tuer le processus, redémarrer

Je suis un débutant absolu et j’essaie de créer un script bash pour randomiser le début et la fin d’une application en ligne de commande. Je prévois de lancer automatiquement le script au démarrage (Crunchbang) après un léger délai avec autostart.sh dans le fichier suivant (disponible ici: http://interwebworld.co.uk/2011/10/23/how-to-launch-programs- automatiquement-au-démarrage-dans-crunchbang-linux / )

(sleep 300s && /home/myuser/Scripts/randomizer.sh) & 

C’est essentiellement ce que je dois accomplir dans le script randomizer.sh, dans un peu de pseudocode:

 start applicationfile wait a random period of time if applicationfile is still running kill its process wait a random period of time exit this script and restart this script else exit this script and restart this script 

Le randomizer.sh tel que je l’ai jusqu’à présent et avec lequel je serais heureux d’avoir de l’aide, est comme suit (contenant les rests du pseudocode), et le délai de sumil trouvé ici: http://blog.buberel.org/2010/ 07 / howto-random-sleep-duration-in-bash.html

 /path/to/applicationfile -s 111.222.333.444 -u username -p password sleep $[ ( $RANDOM % 150 ) + 60 ]m if applicationfile is still running kill $(ps aux | grep '[u]sername' | awk '{print $2}') sleep $[ ( $RANDOM % 150 ) + 60 ]m exec $randomizer.sh else exec $randomizer.sh 

Je “pense” que les parties non-pseudo devraient fonctionner comme elles sont, mais corrigez-moi ou ajustez si je me trompe. La ligne de commande initiale de applicationfile fonctionne comme elle est, et j’ai déjà testé le processus kill line et cela fonctionne comme prévu. Applicationfile n’a pas de moyen intégré pour se terminer à partir de la ligne de commande, mais la connexion morte sur la machine distante sera détruite après 5 minutes de destruction locale, donc le tuer localement est acceptable pour mes besoins.

Ce que je ne sais absolument pas, c’est la ligne au-dessus de kill, qui vérifie si le processus est exécuté en premier lieu. Désolé pour le mur de texte mais je voulais montrer que j’ai déjà fait le maximum.

En bash, $! est le PID du dernier processus lancé, donc quelque chose dans le style de ceci devrait fonctionner:

 mycommand & last_pid=$! sleep( $RANDOM ) kill -KILL $last_pid 

Vous pouvez, bien sûr, fouiller pour changer le signal que vous envoyez, la relation entre $ RANDOM et l’heure à laquelle vous voulez dormir, etc.

Il est peu probable qu’un nouveau processus obtienne le même PID à moins que a) le temps de repos soit très long ou b) que votre machine lance de nombreux processus de courte durée. Sous Linux, les PID sont alloués de manière cyclique avec un maximum de 32 765, de sorte que, grosso modo, il vous aurait fallu lancer de nombreux processus dans le temps de veille pour risquer de toucher le même PID appartenant à un processus différent. Si c’est un risque, vous pouvez append un test (techniquement, il y a une course ici, mais il est très peu probable que cela pose problème). Ce qui suit semble faire ce que vous voulez.

 signal=KILL sleep_a_while () { sleep $[ ( $RANDOM % 150 ) + 60 ]m } while true; do # Note: command launched in background: /path/to/applicationfile -s 111.222.333.444 -u username -p password & # Save PID of command just launched: last_pid=$! # Sleep for a while: sleep_a_while # See if the command is still running, and kill it and sleep more if it is: if ps -p $last_pid -o comm= | grep -qs '^applicationfile$'; then kill -$signal $last_pid 2> /dev/null sleep_a_while fi # Go back to the beginning and launch the command again done 

J’ai remplacé l’auto- exec par une boucle équivalente.

Sur la ligne d’ stderr , la redirection de stderr vers /dev/null est souhaitable à cause d’une course. Le processus peut se terminer naturellement entre le moment où le ps termine et le moment où le kill est exécuté, entraînant un message d’erreur inoffensif. Cette course est inévitable (et sans danger) à moins que le test de l’existence du PID et l’envoi du signal ne coïncident.

S’il est prévu au plus une instance de fichier d’ applicationfile à la fois, cette race peut être complètement évitée en remplaçant:

 # See if the command is still running, and kill it and sleep more if it is: if ps -p $last_pid -o comm= | grep -qs '^applicationfile$'; then kill -$signal $last_pid 2> /dev/null sleep_a_while fi 

Avec:

 killall -q applicationfile && sleep_a_while 

Si cela ne peut pas être utilisé, la variante du test de Keith Reynolds est meilleure, car elle évite un grep inutile, c’est-à-dire en utilisant:

 # See if the command is still running, and kill it and sleep more if it is: if [ "$(ps -p $last_pid -o comm=)" = "applicationfile" ]; then kill -$signal $last_pid 2> /dev/null sleep_a_while fi 

Essayez ce code pour votre randomizer.sh

 min_val=60 range=150 while true ; do run_this_command & last_pid=$! sleep $[ ( $RANDOM % $range ) + $min_val ] { [ "$(ps -p $last_pid -o comm= )" ] && \ [ "$(ps -p $last_pid -o comm= )" = run_this_command ]; } && { kill -KILL $last_pid ;} done 

Quelques notes:

  1. Plutôt que d’utiliser l’instruction exec. Vous pouvez accomplir ce que vous essayez de faire plus simplement en restant dans une boucle. Le randomiser.sh que je présente n’est lu qu’une seule fois depuis le disque dur.
  2. La commande code { [ condition ] && { command ;} && command s’exécute plus rapidement que if [ condition ]; then command, else command; fi if [ condition ]; then command, else command; fi
  3. Avec la variable $ last_pid assignée à la valeur de $ !, la commande ps -p $last_pid -o comm= crachera le nom du processus avec le PID de $last_pid . S’il n’y a pas de PID avec cette valeur, son code existant est 1.

Modification de la période d’attente aléatoire supplémentaire avant l’exigence de démarrage:

 # Minimum and range values for random Wait before start in seconds MinA=60;RangeA=150 # Minimum and range values for random Wait before kill in seconds MinB=60; RangeB=150 # while true ; do sleep $[ ( $RANDOM % $RangeA ) + $MinA ] run_this_command & last_pid=$! sleep $[ ( $RANDOM % $RangeB ) + $MinB ] { [ "$(ps -p $last_pid -o comm= )" ] && \ [ "$(ps -p $last_pid -o comm= )" = run_this_command ] } && \{ kill -KILL $last_pid ;} done