web-dev-qa-db-fra.com

Exécuter le script bash littéralement tous les 3 jours

Je veux exécuter un script Shell littéralement tous les 3 jours. L'utilisation de crontab avec 01 00 */3 * * ne remplira pas réellement la condition, car elle s'exécutera le 31 puis à nouveau le 1 er jour du mois. La syntaxe */3 revient à dire 1,4,7 ... 25,28,31.

Il devrait exister des moyens pour que le script lui-même vérifie les conditions et quitte si 3 jours ne sont pas écoulés. Donc, crontab exécute le script tous les jours, mais le script lui-même vérifiera si 3 jours se sont écoulés.

J'ai même trouvé du code, mais cela m'a donné une erreur de syntaxe, toute aide serait la bienvenue.

if (! (date("z") % 3)) {
     exit;
}

main.sh: line 1: syntax error near unexpected token `"z"'
main.sh: line 1: `if (! (date("z") % 3)) {'
8
Taavi

Pour abandonner immédiatement et quitter un script si la dernière exécution n’est pas encore antérieure à au moins une heure spécifique, vous pouvez utiliser cette méthode qui nécessite un fichier externe contenant la date et l’heure de la dernière exécution.

Ajoutez ces lignes en haut de votre script Bash:

#!/bin/bash

# File that stores the last execution date in plain text:
datefile=/path/to/your/datefile

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Test if datefile exists and compare the difference between the stored date 
# and now with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test -f "$datefile" ; then
    if test "$(($(date "+%s")-$(date -f "$datefile" "+%s")))" -lt "$seconds" ; then
        echo "This script may not yet be started again."
        exit 1
    fi
fi

# Store the current date and time in datefile
date -R > "$datefile"

# Insert your normal script here:

N'oubliez pas de définir une valeur significative sous la forme datefile= et d'adapter la valeur de seconds= à vos besoins ($((60*60*24*3)) est évalué à 3 jours).


Si vous ne voulez pas de fichier séparé, vous pouvez également enregistrer la dernière heure d'exécution dans l'horodatage de modification de votre script. Cela signifie toutefois que toute modification de votre fichier de script réinitialisera le compteur 3 et sera traitée comme si le script était en cours d'exécution.

Pour implémenter cela, ajoutez l'extrait de code ci-dessous en haut de votre fichier de script:

#!/bin/bash

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Compare the difference between this script's modification time stamp 
# and the current date with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test "$(($(date "+%s")-$(date -r "$0" "+%s")))" -lt "$seconds" ; then
    echo "This script may not yet be started again."
    exit 1
fi

# Store the current date as modification time stamp of this script file
touch -m -- "$0"

# Insert your normal script here:

Là encore, n'oubliez pas d'adapter la valeur de seconds= à vos besoins ($((60*60*24*3)) est évalué à 3 jours).

12
Byte Commander

Cron est vraiment le mauvais outil pour cela. Il existe en fait un outil couramment utilisé et sous-appelé appelé at qui pourrait fonctionner. at's principalement conçu pour une utilisation interactive et je suis sûr que quelqu'un trouverait un meilleur moyen de le faire.

Dans mon cas, le script que j'exécute est répertorié dans testjobs.txt et inclut une ligne qui se lit.

Par exemple, j'aurais ceci comme testjobs.txt

echo "cat" >> foo.txt
date >> foo.txt
at now + 3 days < testjobs.txt

J'ai deux commandes innocentes, qui pourraient être vos scripts de coquilles. Je lance echo pour m'assurer que j'ai une sortie déterministe et date pour confirmer que la commande s'exécute selon les besoins. Lorsque vous exécuterez cette commande, il ajoutera un nouveau travail à pendant 3 jours. (J'ai testé avec une minute - ce qui fonctionne)

Je suis sûr que je serai appelé pour la manière dont j'ai abusé, mais c'est un outil pratique pour planifier l'exécution d'une commande à une heure ou x jours après une commande précédente.

12
Journeyman Geek

Tout d’abord, le fragment de code ci-dessus n’est pas conforme à la syntaxe Bash et ressemble à Perl. Deuxièmement, le paramètre z sur date le fait sortir du fuseau horaire numérique. +%j est le numéro du jour. Vous avez besoin:

if [[ ! $(( $(date +%j) % 3 )) ]] ;then
     exit
fi

Mais vous allez toujours voir l'étrangeté en fin d'année:

$ for i in 364 365  1 ; do echo "Day $i, $(( $i % 3 ))"; done
Day 364, 1
Day 365, 2
Day 1, 1

Vous aurez peut-être plus de chance de conserver un nombre dans un fichier et de le tester/le mettre à jour.

3
waltinator

Si vous pouvez simplement laisser le script tourner en permanence, vous pouvez faire:

while true; do

[inert code here]

sleep 259200
done

Cette boucle est toujours vraie, elle exécutera donc toujours le code, puis attendra trois jours avant de recommencer la boucle.

2
mkingsbu

Vous pouvez utiliser anacron au lieu de cron, il est conçu pour faire exactement ce dont vous avez besoin. De la page de manuel:

Anacron peut être utilisé pour exécuter des commandes périodiquement, avec une fréquence spécifiée en jours. Contrairement à cron (8), cela ne signifie pas que la machine tourne en permanence. Par conséquent, il peut être utilisé sur des machines qui ne fonctionnent pas 24 heures sur 24 pour contrôler les tâches quotidiennes, hebdomadaires et mensuelles habituellement contrôlées par cron.

Une fois exécuté, Anacron lit une liste de tâches dans un fichier de configuration, généralement/etc/anacrontab (voir anacrontab (5)). Ce fichier contient la liste des tâches contrôlées par Anacron. Chaque entrée de travail spécifie une période en jours, un délai en minutes, un identificateur de travail unique et une commande Shell.

Pour chaque travail, Anacron vérifie si ce travail a été exécuté au cours des n derniers jours, n étant la période spécifiée pour ce travail. Sinon, Anacron exécute la commande Shell du travail après avoir attendu le nombre de minutes spécifié comme paramètre de délai.

Une fois la commande terminée, Anacron enregistre la date dans un fichier d'horodatage spécial pour ce travail, afin de savoir quand l'exécuter à nouveau. Seule la date est utilisée pour les calculs de l'heure. L'heure n'est pas utilisée.

2
Twinkles