J'ai lu une instruction pour planifier un script le dernier jour du mois:
Remarque:
Le lecteur astucieux se demande peut-être comment définir une commande à exécuter le dernier jour de chaque mois, car vous ne pouvez pas définir la valeur dayofmonth pour couvrir chaque mois. Ce problème a tourmenté les programmeurs Linux et Unix, et a engendré plusieurs solutions différentes. Une méthode courante consiste à ajouter une instruction if-then qui utilise la commande date pour vérifier si la date de demain est 01:00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Ceci vérifie chaque jour à midi pour voir si c'est le dernier jour du mois, et si c'est le cas, cron exécute la commande.
Comment ça [`date +%d -d tomorrow` = 01 ]
marche?
Est-il exact de dire then; command1
?
shell-script
cron
date
test
Calcul
la source
la source
; endif
?[
et pasfi
à la fin. Aussi,%
est spécial dans les crontabs.Réponses:
Abstrait
Le code correct doit être:
Appelez ce script
end_of_month.sh
et l'appel en cron est simplement:Cela exécuterait le script
end_of_month
(qui vérifiera en interne que le jour est le dernier jour du mois) uniquement les jours 28, 29, 30 et 31. Il n'est pas nécessaire de vérifier la fin du mois un autre jour.Ancien poste.
Il s'agit d'une citation tirée du livre «Linux Command Line and Shell Scripting Bible» de Richard Blum, Christine Bresnahan pp 442, troisième édition, John Wiley & Sons © 2015.
Oui, c'est ce qu'il dit, mais c'est faux / incomplet:
fi
.[
les éléments suivants`
.`…`
."$(…)"
;
aprèsthen
Comment puis-je savoir? (enfin, par expérience ☺) mais vous pouvez essayer Shellcheck . Collez le code du livre (après les astérisques) et il vous montrera les erreurs listées ci-dessus plus un "shebang manquant". Voici un script sans erreur dans Shellcheck:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Ce site fonctionne parce que ce qui a été écrit est du "code shell". C'est une syntaxe qui fonctionne dans de nombreux shells.
Certains problèmes que shellcheck ne mentionne pas sont:
Il suppose que la commande date est la version de date GNU. Celui avec une
-d
option qui acceptetomorrow
comme valeur (busybox a une option -d mais ne comprend pas demain et BSD a une-d
option mais n'est pas liée à "l'affichage" de l'heure).Il est préférable de définir le format après toutes les options
date -d tomorrow +'%d'
.L'heure de début cron est toujours en heure locale, ce qui peut faire démarrer une tâche 1 heure plus tôt ou plus tard qu'un compte de jour exact si l'heure d'été (DST) est réglée ou non.
Ce que nous avons fait, c'est un script shell qui pourrait être appelé avec cron. Nous pouvons encore modifier le script pour accepter les arguments du programme ou de la commande à exécuter, comme ceci (enfin, le code correct):
Appelez ce script
end_of_month.sh
et l'appel en cron est simplement:Cela exécuterait le script
end_of_month
(qui vérifiera en interne que le jour est le dernier jour du mois) uniquement les jours 28, 29, 30 et 31. Il n'est pas nécessaire de vérifier la fin du mois un autre jour.Assurez-vous que le chemin correct est inclus. Le PATH à l'intérieur de cron ne sera pas (probablement) le même que le PATH utilisateur.
Notez qu'il existe un script de fin de mois testé (comme indiqué ci-dessous) qui pourrait appeler de nombreux autres utilitaires ou scripts.
Cela évitera également le problème supplémentaire que cron génère avec la ligne de commande complète:
%
fichier même s'il est cité avec'
ou"
(seul un\
fonctionne ici). C'est une manière courante d'échouer dans les tâches cron.Vous pouvez tester si le
end_of_month.sh
script fonctionne correctement à une certaine date (sans attendre la fin du mois pour découvrir qu'il ne fonctionne pas) en le testant avec faketime:la source
date
(ou ledate
buildin de ksh93 si ksh93 a été construit dans le cadre de ast-open) supportedate -d tomorrow +%s
oudate +%s tomorrow
).* * * * * echo "$(date -u +'date %c')" >>~/testfile
ne fonctionnera pas parce que l'on a oublié de citer le\%
(qui devient difficile à déboguer si un seul essai par mois est possible). @KusalanandaEn supposant que les erreurs de syntaxe sont fixes et que la commande a été reformulée légèrement pour être moins verbeuse:
Cela s'exécute
date +%d -d tomorrow
(en supposant que c'est GNUdate
qui est utilisé) pour obtenir la date de demain sous la forme d'un nombre à deux chiffres. Si le numéro est01
, alors aujourd'hui est pas le dernier jour du mois. Dans ce cas, les tests réussissent et necommand1
sont pas exécutés. Le travail est exécuté à midi les jours qui pourraient éventuellement être le dernier jour du mois.La commande d'origine:
Cela a quelques problèmes:
[
.;
directement aprèsthen
.%
est spécial dans les spécifications des tâches cron et doit être échappé comme\%
(voirman 5 crontab
).fi
à la fin qui corresponde à laif
.la source
[ ... ] && command1
au lieu deif...
est que les jours qui ne sont pas le dernier jour du mois, la tâche cron se terminera avec un état de sortie différent de zéro et cette défaillance devra peut-être être signalée. L'utilisation[ "$(...)" != 01 ] || command1
est une autre façon d'éviter le problème.;
entrethen
etcommand1
."
ou'
(sauf\
), le signe de pourcentage%
fera que cron coupera la ligne en deux parties. C'est une façon habituelle de faire échouer cron.Pour planifier le dernier jour de chaque mois, vous pouvez essayer:
0 0 15,L * *
.la source