Forum Linux.debian/ubuntu pb d'accès fichier sous CRON

Posté par . Licence CC by-sa.
0
14
août
2016

Bonjour à tous,

voilà mon souci:
Je souhaite envoyer un message régulièrement donc je demande à CRON de lancer un prog python puis mail.
Ca se passe bien pour une commande mais pour une autre je n'y arrive pas.

voilà la sortie de crontab -l :
0 */2 * * * ps U mosquitto | mail -s "rapportRaspyyy" RRR@gmail.com
===> Cà ça marche.

* * * * * python thermometre.py > gna.txt
* * * * * mail -s "temperature" RRR@gmail.com < gna.txt

Les 2 lignes précédentes fonctionnent quand on les active/ dé-commente l'une ou l'autre.
Par contre quand je dé-commente les 2 lignes, KO !
Je fichier reçu par la fonction mail semble être vide. Le mail est envoyé et est vide.
J'ai un message d'erreur/remarque de mail qui dit à la fin (je vous passe le début):

**Subject: Cron pi@raspberrypi mail -s "temperature" RRR@gmail.com < gna.txt
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:
X-Cron-Env:

mail: Null message body; hope that's ok**

J'ai essayé
- les 2 commandes dans un sens puis l'autre, c'est pareil.
- cat gna.txt > mail… pareil
- cat gna.txt | mail … idem
Le programme python termine par un print(…). Quand je regarde le contenu du fichier il évolue bien comme prévu.

Bref je sèche un peu là. Je me demande si le fichier n'est pas en cours d'utilisation par une commande pendant que l'autre le veut mais ça n'est pas logique.
Si quelqu'un a une idée ?

  • # un seul script pour les gouverner tous

    Posté par . Évalué à 5.

    Une explication plausible (selon moi) est que cron lance les deux scripts quasi en même temps, mais que ta commande d'envoi d'e-mail va suffisamment plus vite que la commande python pour que le fichier gna.txt ait déjà été purgé par ">" mais pas encore mis à jour. Une façon de vérifier ça serait de chronométrer le temps d'exécution de chaque commande.

    Une première solution serait de décaler le traitement des deux commandes (une toute les minutes paires, l'autre toutes les minutes impaires par exemple). Je n'ai pas la syntaxe cron de tête, mais c'est possible. Mais c'est pas terrible parce que ça divise la fréquence du traitement par deux. On pourrait s'en sortir avec deux couples de scripts utilisant deux fichiers d'échanges différents et lancés en alternance avec le premier couple de script, mais c'est très moche, faut pas faire ça :-)

    Une autre façon de régler le problème est d'écrire un script shell qui encapsule les deux commandes (python puis mail) et de lancer ce script à partir de cron. C'est la solution que je recommanderais si tu commençais à vouloir enchaîner beaucoup de commandes.

    Si c'est juste pour ces deux commandes là, tu peux aussi les lancer l'une à la suite de l'autre en utilisant une seule entrée de crontab en utilisant des parenthèses. Genre:

    * * * * * (python thermometre.py > gna.txt; mail -s "temperature" RRR@gmail.com < gna.txt)

    Sinon, pour ça :
    bash
    cat gna.txt > mail…

    normal que ça ne fonctionne pas, le redirection de la sortie de standard (>) va aboutir à interpréter mail comme un fichier de destination et pas comme la commande mail.

    cat gna.txt | mail … idem

    Il y a probablement moyen d'ordonner à la commande mail de lire l'objet de l'e-mail à partir de son entrée standard, et donc d'utiliser une structure python … | mail … , mais manifestement pas aussi simplement qu'avec un |. Je ne connais pas assez les options de mails pour avoir une réponse définitive là dessus (et je n'ai pas du tout envie de lire la page de man de mail :-) )

    • [^] # Re: un seul script pour les gouverner tous

      Posté par . Évalué à 6.

      Si c'est juste pour ces deux commandes là, tu peux aussi les lancer l'une à la suite de l'autre en utilisant une seule entrée de crontab en utilisant des parenthèses. Genre:

      * * * * * (python thermometre.py > gna.txt; mail -s "temperature" RRR@gmail.com < gna.txt)

      Ou beaucoup plus simplement, envoyer directement la sortie de la première commande dans mail:

      python thermometre.py | mail -s "temperature" RRR@gmail.com

      Comme ça, pas besoin de fichier temporaire et pas de problème de temps de démarrage.

      Et si tu a malgré tout besoin (par exemple à des fin de log)) que les données soient enregistrées dans un fichier tu peux intercaler un tee entre les deux:

      python thermometre.py | tee gna.txt | mail -s "temperature" RRR@gmail.com

      (et si c'est pour un log, ajouter l'option --append à tee)

      • [^] # Re: un seul script pour les gouverner tous

        Posté par . Évalué à 2.

        Merci pour toutes vos réponses et surtout explication.
        Merci aussi à GaaaaaAaab (j'ai pas oublié un "a" là ?:) ).

        j'ai opté pour python thermometre.py | mail…
        pour le moment ça me suffit mais vos explications vont me permettre de faire d'autres trucs.

        • [^] # Re: un seul script pour les gouverner tous

          Posté par . Évalué à 2.

          Merci aussi à GaaaaaAaab (j'ai pas oublié un "a" là ?:) ).

          Il y en a un de trop :-)

          Sinon, pour revenir sur ton problème, je re-précise que je suspecte que ça venait de la différence de temps de traitement entre ton programme Python et la commande mail, mais il faudrait tester pour en être vraiment sûr. Ce n'est pas spécialement nécessaire de le faire, mais c'est important de garder en tête que ça reste une hypothèse non confirmée.

          En prenant un peu de hauteur, même si ta solution initiale avait fonctionné, il restait un défaut fondamental: ton traitement est basé sur une séquence logique (la sortie d'une commande est l'entrée de la suivante), mais cron applique une séquence chronologique. Du coup, je ne vois pas vraiment de solution simple avec deux entrées dans cron qui garantirait la séquence logique de ton traitement. Bon, je ne sais pas si ça intéresse grand monde, mais, en y repensant, pour moi, c'est vraiment ça le coeur du problème de ta solution initiale.

          Et, tant qu'on parle de cron, quelques petits ajouts en passant :

          attention à l'environnement : cron transmet directement les commandes qu'on lui passe à un sh non interactif. Dans le contexte des commandes lancées par cron, les variables d'environnement définies dans les .profile, ou autres .bash_profile ne sont pas chargées. Quand on ne le sait pas, on peut perdre pas mal de temps avant de comprendre pourquoi une commande ne marche pas.

          Relativement au commentaire de srayneau ci-dessous , le répertoire de travail d'une commande lancée par cron est le répertoire home de l'utilisateur en question.

  • # whereis

    Posté par . Évalué à 1. Dernière modification le 16/08/16 à 16:05.

    Salut,

    Peut être un problème de path

    Si python et mail ne sont pas dans le même endroit la sortie de l'un ne correspond pas à l'entrée de l'autre.
    Donc en forçant le chemin du fichier gna.txt ? genre

    • * * * * python thermometre.py > ./tmp/gna.txt
    • * * * * mail -s "temperature" RRR@gmail.com < ./tmp/gna.txt
    • [^] # Re: whereis

      Posté par . Évalué à 2.

      Si python et mail ne sont pas dans le même endroit la sortie de l'un ne correspond pas à l'entrée de l'autre.

      La question n'est pas vraiment sur le répertoire dans lequel se trouve les différentes commandes, mais plutôt le répertoire de travail au moment ou elles sont lancées. En l'occurrence, les deux commandes étaient lancées par cron, donc dans le même répertoire de travail (le home de l'utilisateur pour lequel cron exécute ces commandes).

      Si au lieu d'une redirection, les commandes python et mail prenait un nom de fichier comme paramètre, alors, oui, la question de savoir ou chaque commande pense que ce fichier se trouve serait très importante.

      Ceci dit, si on a besoin d'accéder à un fichier particulier, ça peut être pertinent d'utiliser des chemins absolus dans le contexte de cron. J'attire toutefois ton attention sur le fait qu'en ayant ajouté un "." au début de tes chemins, tu en as fait des chemins relatifs plutôt que des chemins absolus. Du coup, tel que tu l'as écrit, c'est similaire à la solution initiale. Ta proposition souffre aussi du fait que si le répertoire local "tmp" n'existe pas, il n'est pas créé par la redirection ">" et du coup, les deux commandes échouent.

      Bref, dans le détail et sur ce cas précis, ta proposition est incorrecte en l'état, mais dans l'absolu, c'est bien de se poser la question des emplacements de fichier (et plus généralement de l'environnement) quand on travaille avec cron.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.