CyberSDF

Reprenez la main sur votre numérique

Cron command not found : corriger le PATH d’une tâche qui marche à la main

un poste de travail sobre vu de trois quarts, ecran eteint, clavier mecanique, carnet ouvert

Une ligne de crontab qui appelle sauvegarde.sh sans chemin échoue alors que la même commande passe dans le terminal, et la cause tient en une valeur : le PATH d’une tâche cron vaut /usr/bin:/bin tant que le crontab ne fixe rien d’autre. Le démon ne reprend ni le PATH de la session, ni celui de ~/.bashrc, ni les alias du shell de connexion.

Sommaire
  1. Le PATH d’une tâche cron vaut /usr/bin:/bin, pas celui de votre terminal
  2. Pourquoi la tâche échoue sans laisser d’erreur visible ?
  3. Trois correctifs, du plus court au plus durable
  4. Trois cas que ces correctifs ne couvrent pas
  5. Cinq réponses pour choisir entre chemin absolu et ligne PATH
  6. Sources

Un script sans bit d’exécution, un chemin relatif ou un interpréteur absent produisent le même échec, et les fondamentaux Linux couvrent ces vérifications avant toute planification. La correction, elle, se joue à trois endroits possibles : la ligne du crontab, sa tête de fichier, ou le script lui-même.

Le PATH d’une tâche cron vaut /usr/bin:/bin, pas celui de votre terminal

Le PATH des tâches cron vient d’une valeur compilée dans le paquet, pas de l’environnement de connexion : avec cron 3.0pl1-197, celui de Debian 13, une tâche reçoit /usr/bin:/bin quand son crontab ne définit pas PATH. Une commande rangée dans /usr/local/bin ou dans /home/alice/bin reste donc introuvable, même si la même ligne répond parfaitement dans un terminal. Le démon ne lit ni .profile ni .bashrc avant de lancer la tâche.

Pour chaque tâche, le démon pose les variables du tableau ci-dessous, dont les valeurs sont fixées par la page de manuel crontab(5) du paquet Debian 13 : SHELL vaut /usr/bin/sh, LOGNAME et HOME viennent de la ligne /etc/passwd du propriétaire du crontab. HOME et SHELL se remplacent dans le crontab, LOGNAME reste figé. La commande de la ligne, elle, est confiée à /usr/bin/sh ou au shell indiqué par SHELL.

Variable Valeur posée pour la tâche Document qui la fixe
SHELL /usr/bin/sh crontab(5), paquet Debian 13
HOME répertoire de la ligne /etc/passwd crontab(5), paquet Debian 13
LOGNAME propriétaire du crontab, non modifiable crontab(5), paquet Debian 13
PATH /usr/bin:/bin sans réglage dans le crontab binaire /usr/sbin/cron, paquet 3.0pl1-197
MAILTO propriétaire du crontab par défaut crontab(5), paquet Debian 13

Le fichier /etc/crontab livré par Debian 13 annonce un PATH plus large, /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin, et ce réglage ne concerne que les tâches écrites dans ce fichier. Les recommandations qui font poser PATH dans /etc/environment ne changent rien pour vos crontabs : la page cron(8) du paquet Debian indique que ces fichiers servent à régler LANG, LC_ALL et LC_CTYPE du démon pour l’encodage des courriels, et qu’ils n’agissent pas sur l’environnement des tâches. Sur Debian, le module PAM pam_env lit bien /etc/environment, mais le contenu du crontab passe après le sien : un PATH hérité de PAM est écrasé dès que le crontab, ou le défaut du paquet, en fournit un.

Pourquoi la tâche échoue sans laisser d’erreur visible ?

Sans serveur de courrier installé, le cron de Debian jette la sortie de la tâche et le message d’erreur part avec elle : le journal ne reçoit que la ligne (CRON) info (No MTA installed, discarding output). Le texte que vous cherchez, du type /usr/bin/sh: 1: /home/alice/bin/sauvegarde.sh: not found, n’est alors visible nulle part. La redirection de sortie règle ce point en une ligne.

Deux traces restent consultables dans le journal systemd : le départ de la tâche et l’abandon de sa sortie. Le cron de Debian journalise le début de chaque tâche par défaut, et le processus enfant qui exécute la commande y apparaît en majuscules, d’où l’étiquette CRON en tête de ligne.

CRON[2143]: (alice) CMD (/home/alice/bin/sauvegarde.sh)
CRON[2143]: (CRON) info (No MTA installed, discarding output)

Pour lire l’erreur elle-même, la sortie se redirige vers un fichier, ce qui évite d’installer un serveur de courrier :

0 22 * * * /home/alice/bin/sauvegarde.sh >> /home/alice/cron.log 2>&1

La commande journalctl -u cron affiche ensuite les départs de tâches, et /home/alice/cron.log contient le message du shell.

Trois correctifs, du plus court au plus durable

Trois gestes suffisent, et chacun agit à un endroit différent : le premier nomme la commande dans la ligne du crontab, le deuxième pose un PATH en tête de crontab, le troisième fixe le PATH dans le script. Le premier répare une ligne isolée, le deuxième couvre toutes les lignes du même fichier, le troisième suit le script quand un service systemd ou un autre script l’appelle. Aucun des trois ne demande de redémarrer le démon : cron relit un crontab modifié.

Un seul échec peut demander un correctif ou les trois, selon l’endroit où le nom manque. Une commande nommée sans chemin relève du premier, un script qui appelle un binaire de /usr/local/bin relève du deuxième, un script déplacé vers un autre utilisateur relève du troisième. Les commandes ci-dessous s’exécutent sous le propriétaire du crontab, sans sudo.

  1. Correctif 1 : le chemin absolu dans la ligne du crontab.

    crontab -e

    Remplacer ensuite la ligne fautive par son chemin complet. Avant :

    0 22 * * * sauvegarde.sh

    Après :

    0 22 * * * /home/alice/bin/sauvegarde.sh

    Ce que vous devez voir : crontab -l renvoie la ligne avec le chemin complet, puis, à la minute prévue, journalctl -u cron affiche CRON[2143]: (alice) CMD (/home/alice/bin/sauvegarde.sh).

  2. Correctif 2 : une ligne PATH en tête du crontab. Elle s’applique aux lignes suivantes du fichier, donc aux scripts qui conservent le PATH hérité.

    PATH=/usr/local/bin:/usr/bin:/bin
    0 22 * * * /home/alice/bin/sauvegarde.sh >> /home/alice/cron.log 2>&1

    Deux pièges sont documentés. Les valeurs d’un crontab ne sont pas développées, donc PATH=$HOME/bin:$PATH et PATH=~/bin:/usr/bin ne donnent pas le chemin attendu, d’après la page crontab(5) du paquet Debian 13 : le tilde ne vaut rien dans ce fichier. Un fichier déposé dans /etc/cron.d n’hérite pas non plus des réglages de /etc/crontab, précise la page cron(8) : chacun porte sa propre ligne PATH.

    Ce que vous devez voir : crontab -l affiche la ligne PATH avant les lignes de planification, et /home/alice/cron.log contient la sortie attendue à l’exécution suivante.

  3. Correctif 3 : le PATH dans le script. Placé après la ligne #!, il ne dépend plus du crontab.

    #!/bin/sh
    PATH=/usr/local/bin:/usr/bin:/bin
    export PATH

    Un service systemd, un autre script ou un second utilisateur héritent alors du même PATH. Pour reproduire l’environnement minimal d’une tâche avant de valider :

    env -i PATH=/usr/bin:/bin HOME="$HOME" /usr/bin/sh -c /home/alice/bin/sauvegarde.sh

    Ce que vous devez voir : le script produit la même sortie que dans le terminal, sans modification du crontab.

Trois cas que ces correctifs ne couvrent pas

Un chemin absolu et une ligne PATH réparent le nom des commandes, et rien de plus. Trois comportements du format crontab restent hors de leur portée, tous documentés dans les pages de manuel du paquet Debian 13. Le premier concerne le caractère %, transformé en retour à la ligne dans le champ commande : une ligne qui appelle date +%F ne reçoit pas ce qu’elle attend, et le % s’écrit \% pour passer tel quel.

Le deuxième touche la fin du fichier. La page crontab(1) du paquet indique qu’une dernière ligne sans retour à la ligne fait considérer le crontab comme cassé, avec un refus à l’installation ; la commande crontab -n monfichier teste la syntaxe sans rien installer, ce qui évite de découvrir le problème après un enregistrement.

Le troisième est une limite de taille : la même page fixe à 998 caractères la longueur maximale du champ commande. Une ligne trop longue se coupe, et la commande tronquée échoue. Ces trois cas se repèrent avant la planification, en relisant le fichier avec crontab -l.

Cinq réponses pour choisir entre chemin absolu et ligne PATH

Le choix entre les deux formes dépend de la portée voulue, pas de la longueur de la ligne : une ligne PATH couvre tout un crontab et les scripts qui gardent le PATH hérité, un chemin absolu ne couvre qu’une commande mais survit à la copie d’une ligne vers un autre fichier. Les réponses ci-dessous portent sur les valeurs par défaut du paquet Debian 13, sur la lecture des erreurs, sur les tests qui evitent une attente d’une minute, et sur les cas où un script appelle un binaire rangé ailleurs.

Faut-il un chemin absolu ou une ligne PATH dans le crontab ?

Les deux formes sont valides et se combinent. Un chemin absolu dans la ligne ne couvre qu’une commande, alors qu’une ligne PATH en tête de crontab s’applique à toutes les lignes du fichier et aux scripts qui gardent le PATH hérité. Avec le paquet Debian 13, un crontab sans PATH donne /usr/bin:/bin à ses tâches : la ligne PATH sert dès qu’une commande vit dans /usr/local/bin ou /home/alice/bin.

Où lire l’erreur d’une tâche qui tourne la nuit ?

Deux sources suffisent. journalctl -u cron montre les départs de tâches, du type CRON[2143]: (alice) CMD (/home/alice/bin/sauvegarde.sh), et la sortie se récupère en la redirigeant vers un fichier avec >> /home/alice/cron.log 2>&1. Sans serveur de courrier, le cron de Debian jette cette sortie après la ligne (CRON) info (No MTA installed, discarding output) : installer un MTA n’est pas nécessaire pour lire une erreur.

Comment tester une tâche sans attendre la minute suivante ?

Le paquet Debian 13 documente cron -N, qui exécute tout de suite les tâches dont l’horaire correspond à la minute en cours, puis rend la main ; cette option n’existe pas dans le cron de Debian 12. Pour vérifier un script seul, env -i PATH=/usr/bin:/bin HOME="$HOME" /usr/bin/sh -c /home/alice/bin/sauvegarde.sh reproduit l’environnement minimal d’une tâche. La syntaxe du fichier se contrôle avec crontab -n monfichier, sans rien installer.

Pourquoi PATH=~/bin:/usr/bin ne donne-t-il rien ?

La page crontab(5) du paquet Debian 13 indique que les valeurs d’environnement d’un crontab ne subissent ni substitution de variables ni développement du tilde. PATH=~/bin:/usr/bin et PATH=$HOME/bin:$PATH ne produisent donc pas le chemin attendu, et le réglage s’écrit en clair, par exemple PATH=/home/alice/bin:/usr/bin:/bin. La règle vaut pour toutes les valeurs du fichier, pas seulement pour PATH.

Un fichier placé dans /etc/cron.d hérite-t-il du PATH de /etc/crontab ?

Non : la page cron(8) du paquet Debian précise que les fichiers de /etc/cron.d sont indépendants de /etc/crontab et n’héritent pas de ses variables d’environnement. Chaque fichier porte donc sa propre ligne PATH, placée avant ses lignes de planification. Ces fichiers appartiennent à root, ne doivent pas être modifiables par le groupe ni par les autres, et leur nom ne peut pas contenir de point.

Sources