Comment (et pourquoi) empêcher un script Bash de se relancer trop tôt
Sommaire
Liens rapides
-
Stockage et récupération de l'heure
-
Utile dans d’autres scénarios
Il est parfois utile de s'assurer qu'un script shell Bash ne s'exécute pas trop fréquemment. Voici une méthode astucieuse pour définir une limite de temps qui doit expirer avant que le script puisse s'exécuter à nouveau.
Prenez une pause
En fonction de ce qu'il fait et des autres processus qu'il peut lancer, un script Bash peut consommer autant de RAM et de temps CPU que n'importe quel autre processus gourmand en ressources. Il peut être utile de limiter la fréquence à laquelle un tel script peut être lancé.
L'imposition d'une période de répit entre chaque exécution d'un script lourd permet d'éviter qu'il ne monopolise les ressources. Les scripts coûteux en termes de calcul peuvent monopoliser les ordinateurs au point que les autres utilisateurs subissent une baisse de performances. Dans les cas extrêmes, si le script provoque une forte rotation du disque, par exemple, il peut même accélérer la disparition de votre matériel.
Bien sûr, concevoir un système qui limite le temps nécessaire pour relancer un script ajoute du code à votre script et lui donne une tâche supplémentaire à accomplir. Cela peut sembler contre-productif, mais si les contrôles sont légers et rapides, leurs faibles frais généraux sont largement compensés par les économies de ressources qu'ils permettent.
Notre stratégie basée sur le temps
Nous souhaitons imposer une période de temps minimale qui doit expirer avant qu'un script puisse être répété. Nous appellerons cette période l'intérim. Nous la définirons comme le temps entre la fin de l'exécution précédente et le début de la nouvelle exécution.
Nous devons enregistrer l'heure à laquelle le script se termine, afin de pouvoir la récupérer la prochaine fois que le script sera lancé. Comme le script peut facilement déterminer l'heure actuelle, il peut calculer la différence entre son heure de lancement et l'heure de fin du script précédent.
Si cette différence est inférieure à notre valeur intermédiaire acceptable, le script se fermera.
Le temps sous Linux
Linux compte les secondes depuis la (deuxième) époque Linux, qui s'est produite à minuit le 1er janvier 1970, UTC. Nous pouvons voir l'heure et la date en exécutant la commande date.
date
Nous pouvons passer des spécificateurs de format à date pour obtenir la sortie dans différents rendus. Pour voir le temps en secondes depuis l'époque, utilisez un « s » minuscule :
date +%s
Le fait de pouvoir accéder à l'heure sous forme d'un seul entier facilite grandement la comparaison de deux heures et la détermination de l'intervalle de temps qui les sépare. C'est parfait pour nos besoins et nous en ferons bon usage.
Stockage et récupération de l'heure
Nous pouvons facilement écrire l'heure dans un fichier, simplement en redirigeant la sortie de la commande date. Nous pouvons utiliser cat pour vérifier que cela a fonctionné.
date +%s > temp.dat
cat temp.dat
Cela nous donne un moyen de stocker notre horodatage. Notez que nous utilisons un seul > pour la redirection, donc le fichier est recréé à chaque fois et ne contient qu'une seule entrée.
Dans notre script, nous devons ouvrir le fichier d'horodatage et lire la valeur enregistrée. Cette valeur doit être conservée dans une variable pour que notre script puisse l'utiliser.
Cela semble assez compliqué, mais il existe une astuce simple que nous pouvons utiliser. Dans notre script, nous utiliserons la commande source pour lire le fichier d'horodatage. Les commandes à l'intérieur du fichier source sont exécutées comme s'il s'agissait de commandes à l'intérieur de notre script.
Lorsque nous enregistrons l'horodatage, nous enregistrons en fait une commande qui crée une variable et lui attribue la valeur temporelle. Une fois le fichier source, notre script exécute cette commande, crée la variable et stocke la valeur temporelle dans la variable, donc tout est fait pour nous.
Nous pouvons vérifier ce processus sur la ligne de commande. Nous composons et écrivons une commande dans un fichier. La commande crée une variable appelée previous_exit qui est définie sur le nombre de secondes depuis l'époque. Nous extrayons le fichier. Nous vérifions ensuite qu'une variable appelée previous_exit existe désormais et voyons quelle valeur elle contient.
echo "previous_exit=$(date +%s)" > timestamp.log
source timestamp.log
echo $previous_exit
Si nous examinons le contenu du fichier, nous pouvons vérifier que la valeur détenue par la variable est celle qui se trouve dans le fichier.
cat timestamp.log
C'est une solution simple et agréable pour stocker et récupérer notre valeur temporelle.
Mettre tout cela ensemble
Passons en revue les différents éléments du script.
Mon script va stocker les horodatages dans un fichier appelé .timestamp.log. Notez que le premier caractère est un point « . » qui signifie qu'il s'agit d'un fichier caché. Il va être stocké dans mon répertoire personnel.
Le script crée une variable appelée timestamp_log pour contenir le chemin et le nom du fichier.
Ensuite, une fonction appelée set_timestamp est définie. Lorsqu'elle est appelée, cette fonction écrit la valeur qui lui est transmise dans le fichier timestamp.log.
#!/bin/bash
timestamp_log="/home/dave/.timestamp.log"
set_timestamp() {
echo "previous_exit=$1" > $timestamp_log
}
Parce que le fichier timestamp.log est mis à jour (et créé s'il n'existe pas) lorsque le script sortiesla toute première fois que le script s'exécute, le fichier timestamp.log n'existera pas. Cela poserait un problème lorsque le script essaierait de le lire.
Pour résoudre ce problème et se protéger contre les situations où le fichier timestamp.log aurait pu être supprimé, nous testons l'existence du fichier. S'il n'existe pas, nous le créons en y stockant une valeur temporelle fictive de zéro.
if ( ! -f $timestamp_log ); then
set_timestamp 0
fi
Nous pouvons maintenant rechercher le fichier en toute sécurité et lire l'instruction qu'il contient. Cela définit la variable previous_exit sur l'horodatage précédent.
source $timestamp_log
Maintenant que nous avons la valeur de l'horodatage, nous pouvons calculer la période intermédiaire entre l'horodatage précédent et l'heure actuelle.
interim=$(( $(date +%s)-$previous_exit ))
Nous pouvons maintenant effectuer un test simple pour voir si suffisamment de temps s'est écoulé pour que le script soit autorisé à s'exécuter. J'utilise une valeur arbitraire et courte de cinq secondes pour le test.
if (( $interim <= 5 )); then
echo "Too soon... $interim seconds..."
exit 1;
fi
echo "Running..."
Si la période intermédiaire est supérieure à cinq secondes, le script peut continuer. Une fois terminé, nous écrivons l'heure actuelle dans le fichier timestamp.log en appelant notre fonction set_timestamp.
set_timestamp $(date +%s)exit 0
Voici le script complet.
#!/bin/bash
timestamp_log="/home/dave/.timestamp.log"
set_timestamp() {
echo "previous_exit=$1" > $timestamp_log
}
if ( ! -f $timestamp_log ); then
set_timestamp 0
fi
source $timestamp_log
interim=$(( $(date +%s)-$previous_exit ))
if (( $interim <= 5 )); then
echo "Too soon... $interim seconds..."
exit 1;
fi
set_timestamp $(date +%s)
echo "Running..."
exit 0
Copiez ce fichier dans votre éditeur préféré et enregistrez-le sous forme de fichier appelé tc.sh. N'oubliez pas de modifier la valeur timestamp_log= sur la ligne 4 pour qu'elle pointe vers l'emplacement sur votre ordinateur où le fichier timestamp.log doit être stocké.
Rendez votre script exécutable.
chmod +x tc.sh
Et maintenant nous pouvons l'exécuter.
./tc.sh
Les tentatives d'exécution ultérieures au cours de la période d'exclusion de cinq secondes s'arrêtent automatiquement. Une fois les cinq secondes écoulées, nous pouvons exécuter à nouveau le script.
Utile dans d’autres scénarios
N'oubliez pas que si votre script a une exécution ramifiée et peut se terminer à différents points du script, vous devrez appeler set_timestamp avant chaque sortie possible. C'est pourquoi il valait la peine de créer la fonction set_timestamp, même si elle n'est utilisée que deux fois dans ce script.
L'astuce consistant à stocker le nom de la variable et sa valeur dans un fichier source peut être exploitée pour lire un fichier de configuration. Il vous suffit d'écrire une liste de noms de variables et de leurs valeurs dans un fichier et de le sourcer à partir de votre script.