Dans la catégorie « astuces pour amoureux de la ligne de commande sous GNU/Linux », voici une petite commande qui peut s’avérer pratique dans le cas de certains développements en Bash. La simplicité de ce code n’a d’égal que sa beauté ! Bien entendu, cette remarque hautement poétique reste subjective…
Pour une raison ou pour une autre, on peut avoir besoin de vérifier si la date du jour est le dernier jour du mois. Sauf que le dernier jour du mois peut être un 28, un 29, un 30 ou un 31.
La commande date du projet GNU permet de retourner une date autre que celle du jour. Il suffit alors de vérifier si « demain » sera le premier jour du mois suivant, et d’exécuter la commande de son choix en conséquence.
test `date +'%d' -d '1 day'` = "1" && echo "hello" || echo "world"
La ligne ci-dessus exécute la commande date en ajoutant « 1 jour » à la date actuelle. Le « %d » permet de récupérer le numéro du jour dans le mois. Si le test confirme que demain nous serons le 1er, alors le terminal affiche « hello » ; dans le cas contraire, le terminal affiche « world ».
Une manière plus académique d’écrire ce code au sein d’un script Bash, pourrait être l’exemple ci-dessous qui donnera le même résultat.
demain=`date +'%d' -d '1 day'` if test "$demain" = "1" then echo "hello" else echo "world" fi
Moi, pour savoir si c’est le dernier jour, du mois, il me suffit de compter sur mes phalanges……
Et ça fonctionne très bien……
(une petite exception pour les années bissextiles)
Si seulement on avait pu greffer des phalanges aux ordinateurs ! Comme ça, même pas besoin d’inventer l’algèbre de Boole (non, ce n’est pas une histoire de fesses avec des matheux) !!!
Concernant les années bissextiles, ça n’a rien de compliqué : tu calcules le modulo 4 de l’année concernée ; si le résultat est égal à 0, alors ta deuxième phalange aura un poids de 29 au lieu de 28 ; sinon, bah c’est 28… Ce qui donnera, très logiquement, en Bash :
test $((`date +’%Y’` % 4)) = ‘0’ && echo ’29’ || echo ’28’ 😎
Tiens, c’est un sujet que j’ai traité dernièrement. Voici un extrait de mon implémentation :
dans le crontab :
# chaque dernier lundi du mois à 3h du matin
# pour tous les mois sauf février :
0 3 25-31 1,3,4,5,6,7,8,9,10,11,12 * monscript
# pour février
0 3 22-29 2 * monscript
dans le fichier monscript :
un bout de ligne qui appel un sous script xDayCompare et retourne 0 ou 1 pour savoir si c’est le bon jour
dans le fichier xDayCompare :
#!/bin/bash
xDay=’Mon’ # c’est le lundi qui m’intéresse et mon OS est en english (et j’ai fait le choix d’avoir le numéro de jour en lettre pour une meilleure compréhension plutôt que du numérique avec date +%u
TODay=$(eval ‘date +%a’)
if [ $TODay != $xDay ]; then
echo ‘KO, nous ne sommes pas le lundi’
exit 1
fi
Avec crontab, tu pouvais aussi très bien faire comme ceci :
0 3 22-29 2 1 monscript
0 3 25-31 1,3,4,5,6,7,8,9,10,11,12 1 monscript
Ou bien une seule ligne (exemple similaire sur Wikipedia) :
0 3 22-31 * 1 test `date +’%d’` -gt `date +’%d’ -d ‘7 day’` && monscript
Le 1 final permettant de lancer monscript uniquement les lundis.
c’est une bonne proposition mais le problème c’est que cette solution n’a pas marché dans mon cas : d’où un xDayCompare.
En effet, lors du test, le crontab a envoyé un mail avec error car, d’après une recherche sur le net, le crontab ne supporte pas les tests.
Du coup, le fameux test a été externalisé dans un script indépendant.
Par ailleurs, as-tu essayé concrètement pour savoir si ca fonctionne ?
Oui, tu as raison, mon exemple n’est pas parfait.
En fait, dans crontab, lorsque tu veux utiliser une commande externe, il est obligatoire de saisir le chemin absolu de celle-ci. Avec un petit which test, par exemple, j’obtiens /usr/bin/test, puis il faut recommencer avec la commande date… Bref, c’est un peu lourdingue à la fin…
Après, tout dépend du cas rencontré : si tu souhaites exécuter un binaire, saisir le test dans crontab t’évite d’écrire un script pour deux lignes. A l’inverse, si tu exécutes un script-maison, autant mettre un max de choses dedans, pourvu qu’il reste suffisamment modulaire et évolutif pour anticiper les futurs besoins.
Un compromis intéressant peut être un script de fonctions communes : ainsi, tu mutualises ton code dans tous tes scripts, et un petit source mesfonctions.sh permet d’en profiter directement dans le terminal comme s’il s’agissait de commandes classiques. Par contre, pas sûr que ça marche en Shell…
On peut effectivement imaginer une fonction dont le paramètre d’entrée est le jour souhaité.
Comme ca la fonction devient générique, indépendante du jour souhaité et donc réutilisable.
@Zoher
En tout cas, je viens de vérifier la commande test dans crontab : avec le chemin absolu, tout fonctionne très bien ! 😉
Avec :
0 3 22-31 * 1 /usr/bin/test `date +’%d’` -gt `date +’%d’ -d ‘7 day’` && /le_chemin/monscript
?
@Zoher
Non, je n’ai pas essayé cet exemple précis. Je viens de jouer un peu avec ton problème, et j’ai obtenu des résultats concluants. La difficulté réside surtout dans l’échappement des bons caractères, en l’occurrence les deux ‘%’.
L’exemple ci-dessous fonctionne :
* * 5 * 3 /usr/bin/test `date +’%d’` -gt `date +’%d’ -d ‘7 day’` && echo ‘hello’ || echo ‘world’ > /home/benoit/titi.txt
NB : j’ai limité la cron aux mercredis 5, hein… 😉