Comment faire en sorte que CRON appelle les bons PATH

124

J'essaie de faire en sorte que cron appelle les bons PATH. Lorsque j'exécute un script Python à partir du shell, le script fonctionne correctement car il utilise les PATH définis dans bashrc, mais lorsque j'utilise cron, tous les PATH ne sont pas utilisés à partir de bashrc. Y a-t-il un fichier dans lequel je peux entrer les PATH pour cron comme bashrc ou un moyen d'appeler les PATH à partir de bashrc?

Désolé, je ne pense pas avoir formulé cela correctement, je peux exécuter le script correct (ce qui signifie que le PATH vers le script dans crontab n'est pas le problème ici), c'est juste lorsque ce script est en cours d'exécution, je lance une construction et cela utilise le PATHs définis .bashrc. Lorsque .bashrcj'exécute le script lorsque je suis connecté, les PATH sont insérés. Puisque cron ne s'exécute pas dans un shell en soi, il n'intervient pas .bashrc. Existe-t-il un moyen d'extraire cela sans avoir à écrire un wrapper de script bash?

chrissygormley
la source
Jetez également un œil à la suggestion donnée ici pour savoir comment faire fonctionner les paramètres bashrc pour cronjobs: stackoverflow.com/q/15557777/1025391
moooeeeep
2
La commande magique, simple et correcte pour que votre profil soit inclus dans l'environnement actuel est source /etc/profile, il devrait manger .bashrcet beaucoup d'autres choses potentiellement manquantes pour vous. Le sourcing de profil explicite devient très utile si vous voulez que certains scripts s'exécutent de manière "autonome", il protège également des environnements étranges et ainsi ...
exa
1
@exa +100 Cela fait fonctionner les shscripts appelés par crontab. Vous pouvez confirmer qu'il met à jour le chemin en ajoutant un travail comme * * * * * echo $PATH > ~/crontab_path.txtet en vérifiant le fichier après une minute.
geotheory

Réponses:

177

J'ai utilisé /etc/crontab. J'ai utilisé viet entré dans les CHEMINS dont j'avais besoin dans ce fichier et l'ai exécuté en tant que root. Le crontab normal écrase les PATH que vous avez configurés. Un bon tutoriel sur la façon de procéder .

Le fichier cron du système ressemble à ceci:

This has the username field, as used by /etc/crontab.
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file.
# This file also has a username field, that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user   command
42 6 * * *   root    run-parts --report /etc/cron.daily
47 6 * * 7   root    run-parts --report /etc/cron.weekly
52 6 1 * *   root    run-parts --report /etc/cron.monthly
01 01 * * 1-5 root python /path/to/file.py
chrissygormley
la source
17
Cela fonctionne avec crontab -e au niveau de l'utilisateur et c'est aussi plus sûr.
Robert Brisita
2
Puis-je utiliser bash au lieu de sh?
qed
1
il est étrange (pour moi) que le PATH par défaut défini dans / etc / crontab comme indiqué par @chrissygormley, et également défini dans mon (Ubuntu) crontab, soit différent du chemin dans / etc / environment, en particulier il met / sbin et / bin avant / usr / sbin et / usr / bin. J'ai maintenant changé cela dans mon / etc / crontab pour le rendre identique à l'environnement utilisateur.
scoobydoo
Ne fonctionne pas pour moi ... Je suis en train de générer du contenu cron dans un fichier. Cron s'exécute, le fichier crée mais il n'y met aucun contenu.
Volatil3
2
Il semble que tous les chemins définis dans ne /etc/crontabsoient pas disponibles pour cron lors de l'exécution en tant que root dans Ubuntu 14.04. ( sudo crontab -e)
David Oliver
50

Très probablement, cron fonctionne dans un environnement très restreint. Vérifiez les variables d'environnement que cron utilise en ajoutant un travail factice qui se vide envdans un fichier comme celui-ci:

* * * * * env > env_dump.txt

Comparez cela avec la sortie d' envune session shell normale.

Vous pouvez ajouter vos propres variables d'environnement au crontab local en les définissant en haut de votre crontab.

Voici une solution rapide à ajouter $PATHà la crontab actuelle:

# echo PATH=$PATH > tmp.cron
# echo >> tmp.cron
# crontab -l >> tmp.cron
# crontab tmp.cron

Le crontab résultant ressemblera à la réponse de chrissygormley, avec PATH défini avant les règles de crontab.

joemaller
la source
22

Vous devez mettre des chemins complets dans votre fichier crontab. C'est l'option la plus sûre.
Si vous ne voulez pas faire cela, vous pouvez mettre un script wrapper autour de vos programmes et y définir le PATH.

par exemple

01 01 * * * command

devient:

01 01 * * * /full/path/to/command

De plus, tout ce qui est appelé à partir de crondoit être très prudent sur les programmes qu'il exécute et probablement définir son propre choix pour la PATHvariable.

ÉDITER:

Si vous ne savez pas où se trouve la commande que vous souhaitez exécuter à which <command>partir de votre shell, elle vous indiquera le chemin.

EDIT2:

Ainsi, une fois que votre programme est en cours d'exécution, la première chose à faire est de définir PATHet toute autre variable requise (par exemple LD_LIBRARY_PATH) aux valeurs requises pour que le script s'exécute.
Fondamentalement, au lieu de réfléchir à la manière de modifier l'environnement cron pour le rendre plus adapté à votre programme / script, faites en sorte que votre script gère l'environnement qui lui est donné, en définissant un environnement approprié au démarrage.

Douglas Leeder
la source
1
si c'est sur votre chemin, utilisez `` quelle commande '' et cela vous donnera le chemin complet
Paul Whelan
@Douglas Leeder - Quand vous dites mettre le chemin complet dans cron, voulez-vous dire le mettre dans crontab ou dans un autre fichier? Si c'est comment procéder si la commande cron est: '01 01 * * * commande '. Merci
chrissygormley
@chrissygormley - Oui crontab.
Douglas Leeder
Désolé, il doit y avoir une certaine confusion. J'ai reformulé la question ci-dessus.
chrissygormley
16

Définir PATH juste avant la ligne de commande dans mon crontab a fonctionné pour moi:

* * * * * PATH=$PATH:/usr/local/bin:/path/to/some/thing
myrho
la source
préfère cette façon. ou spécifiez le chemin complet du script.
zw963
5
Je ne pense pas que le chemin continuera de grandir, à chaque fois que son exécution sera un nouvel environnement, avec une nouvelle copie de PATH ...
jjcf89
Peut confirmer que @ jjcf89 est correct, PATH est frais à chaque exécution.
electrovir
14

Ajouter une définition PATH dans le crontab utilisateur avec des valeurs correctes aidera ... J'ai rempli la mienne avec juste:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Et c'est suffisant pour que tous mes scripts fonctionnent ... Incluez-y n'importe quel chemin personnalisé si vous en avez besoin.

Treviño
la source
1
Pour un utilisateur crontab, cela devrait être la bonne réponse. Tout le monde sur un système ne peut pas modifier /etc/crontab. C'est la réponse la plus simple au niveau de l'utilisateur. Bon travail @ Treviño. Votez si vous êtes d'accord.
frederickjh
14

Faites fonctionner vos variables pour vous, cela vous permettra d'accéder

Définissez votre PATH dans /etc/profile.d/*.sh

Variables d'environnement à l'échelle du système

Les fichiers avec l'extension .sh dans le répertoire /etc/profile.d sont exécutés à chaque fois qu'un shell de connexion bash est entré (par exemple lors de la connexion depuis la console ou via ssh), ainsi que par le DisplayManager lorsque la session de bureau se charge.

Vous pouvez par exemple créer le fichier /etc/profile.d/myenvvars.sh et définir des variables comme ceci:

export JAVA_HOME=/usr/lib/jvm/jdk1.7.0
export PATH=$PATH:$JAVA_HOME/bin

Exécutez crontab avec l'option de connexion!

CRONTAB exécuter un script ou une commande avec des variables d'environnement

0 9 * * * cd /var/www/vhosts/foo/crons/; bash -l -c 'php -f ./download.php'
0 9 * * * cd /var/www/vhosts/foo/crons/; bash -l -c download.sh
Artistan
la source
11

Problème

Votre script fonctionne lorsque vous l'exécutez à partir de la console mais échoue dans cron.

Cause

Votre crontab n'a pas les bonnes variables de chemin (et éventuellement le shell)

Solution

Ajoutez votre shell actuel et accédez au crontab

Script pour le faire pour vous

#!/bin/bash
#
# Date: August 22, 2013
# Author: Steve Stonebraker
# File: add_current_shell_and_path_to_crontab.sh
# Description: Add current user's shell and path to crontab
# Source: http://brakertech.com/add-current-path-to-crontab
# Github: hhttps://github.com/ssstonebraker/braker-scripts/blob/master/working-scripts/add_current_shell_and_path_to_crontab.sh

# function that is called when the script exits (cleans up our tmp.cron file)
function finish { [ -e "tmp.cron" ] && rm tmp.cron; }

#whenver the script exits call the function "finish"
trap finish EXIT

########################################
# pretty printing functions
function print_status { echo -e "\x1B[01;34m[*]\x1B[0m $1"; }
function print_good { echo -e "\x1B[01;32m[*]\x1B[0m $1"; }
function print_error { echo -e "\x1B[01;31m[*]\x1B[0m $1"; }
function print_notification { echo -e "\x1B[01;33m[*]\x1B[0m $1"; }
function printline { 
  hr=-------------------------------------------------------------------------------------------------------------------------------
  printf '%s\n' "${hr:0:${COLUMNS:-$(tput cols)}}"
}
####################################
# print message and exit program
function die { print_error "$1"; exit 1; }

####################################
# user must have at least one job in their crontab
function require_gt1_user_crontab_job {
        crontab -l &> /dev/null
        [ $? -ne 0 ] && die "Script requires you have at least one user crontab job!"
}


####################################
# Add current shell and path to user's crontab
function add_shell_path_to_crontab {
    #print info about what's being added
    print_notification "Current SHELL: ${SHELL}"
    print_notification "Current PATH: ${PATH}"

    #Add current shell and path to crontab
    print_status "Adding current SHELL and PATH to crontab \nold crontab:"

    printline; crontab -l; printline

    #keep old comments but start new crontab file
    crontab -l | grep "^#" > tmp.cron

    #Add our current shell and path to the new crontab file
    echo -e "SHELL=${SHELL}\nPATH=${PATH}\n" >> tmp.cron 

    #Add old crontab entries but ignore comments or any shell or path statements
    crontab -l | grep -v "^#" | grep -v "SHELL" | grep -v "PATH" >> tmp.cron

    #load up the new crontab we just created
    crontab tmp.cron

    #Display new crontab
    print_good "New crontab:"
    printline; crontab -l; printline
}

require_gt1_user_crontab_job
add_shell_path_to_crontab

La source

https://github.com/ssstonebraker/braker-scripts/blob/master/working-scripts/add_current_shell_and_path_to_crontab.sh

Exemple de sortie

Exemple de sortie add_curent_shell_and_path_to_crontab.sh

Brakertech
la source
3

Sur mon AIX, cron récupère ses variables d'environnement de / etc / environment en ignorant ce qui est défini dans le .profile.

Edit: J'ai également extrait quelques boîtes Linux de différents âges et celles-ci semblent également avoir ce fichier, donc ce n'est probablement pas spécifique à AIX.

J'ai vérifié cela en utilisant la suggestion cron de joemaller et en vérifiant la sortie avant et après l'édition de la variable PATH dans / etc / environment.

Van Amburg
la source
3

Si vous ne voulez pas avoir à effectuer les mêmes modifications à différents endroits, procédez à peu près comme suit:

* * * * * . /home/username/.bashrc && yourcommand all of your args

Le . space, puis le chemin vers .bashrc et la commande && sont la magie pour obtenir les modifications de votre environnement dans le shell bash en cours d'exécution. Aussi, si vous voulez vraiment que le shell soit bash, c'est une bonne idée d'avoir une ligne dans votre crontab:

SHELL=/bin/bash

J'espère que cela aide quelqu'un!

Wade Chandler
la source
2

L'environnement par défaut des tâches cron est très rare et peut être très différent de l'environnement dans lequel vous développez vos scripts python. Pour un script qui peut être exécuté dans cron, tout environnement dont vous dépendez doit être défini explicitement. Dans le fichier cron lui-même, incluez les chemins complets vers les exécutables python et vers vos scripts python.

foule
la source
2

Je sais que cela a déjà été répondu, mais j'ai pensé que le sien serait utile à certains. J'ai eu un problème similaire que j'ai récemment résolu ( trouvé ici ) et voici les points saillants des étapes que j'ai suivies pour répondre à cette question:

  1. assurez-vous que vous avez les variables dont vous avez besoin dans PYTHONPATH (trouvées ici et ici et pour plus d'informations ici) dans le .profile ou .bash_profile pour tout shell dans lequel vous voulez tester votre script pour vous assurer qu'il fonctionne.

  2. éditez votre crontab pour inclure les répertoires nécessaires pour exécuter votre script dans un travail cron (trouvé ici et ici)

    a) assurez-vous d'inclure le répertoire racine dans la variable PATH (.) comme expliqué ici (fondamentalement, si vous exécutez un exécutable avec votre commande, il doit être en mesure de trouver root ou le répertoire où l'exécutable est stocké) et probablement ces (/ sbin: / bin: / usr / sbin: / usr / bin)

  3. dans votre fichier crontab, créez un cronjob qui changera de répertoire vers le répertoire où vous avez exécuté avec succès le script auparavant (c'est-à-dire Users / user / Documents / foo)

    a) Cela ressemblera à ce qui suit:

    * * * * cd /Users/user/Documents/foo; bar -l doSomething -v 
    
dérisoire
la source
2

@Trevino: votre réponse m'a aidé à résoudre mon problème. Cependant, pour un débutant, essayez de donner une approche étape par étape.

  1. Obtenez votre installation actuelle de java via $ echo $JAVA_HOME
  2. $ crontab -e
  3. * * * * * echo $PATH- cela vous permet de comprendre quelle est la valeur PATH actuellement utilisée par crontab. Exécutez crontab et récupérez la valeur $ PATH utilisée par crontab.
  4. Maintenant, modifiez à nouveau crontab pour définir le chemin de la corbeille java souhaitée: a) crontab -e; b) PATH=<value of $JAVA_HOME>/bin:/usr/bin:/bin(c'est un exemple de chemin); c) maintenant votre travail / script planifié comme */10 * * * * sh runMyJob.sh &; d) retirer echo $PATHde crontab car ce n'est pas nécessaire maintenant.
Ram Dwivedi
la source
2

Définissez le PATH requis dans votre cron

crontab -e

Edit: Appuyez sur i

PATH=/usr/local/bin:/usr/local/:or_whatever

10 * * * * your_command

Sauvegarder et quitter :wq

Yogesh Yadav
la source
1

La solution de contournement la plus simple que j'ai trouvée ressemble à ceci:

* * * * * root su -l -c command

Cet exemple invoque su tant qu'utilisateur root et démarre le shell avec l'environnement complet de l'utilisateur, y compris $ PATH, défini comme s'il était connecté. Il fonctionne de la même manière sur différentes distributions, est plus fiable que l'approvisionnement .bashrc (qui n'a pas fonctionné pour me) et évite de coder en dur des chemins spécifiques qui peuvent être un problème si vous fournissez un exemple ou un outil de configuration et que vous ne savez pas quelle distribution ou disposition de fichier sur le système de l'utilisateur.

Vous pouvez également spécifier le nom d'utilisateur après susi vous voulez un utilisateur différent de root, mais vous devriez probablement laisser le rootparamètre avant la sucommande car cela garantit qu'il sudispose de privilèges suffisants pour basculer vers n'importe quel utilisateur que vous spécifiez.


la source
-3

Si vous utilisez, webminvoici les étapes pour définir la PATHvaleur:

System
  -> Scheduled Cron Jobs
       -> Create a new environment variable
            -> For user: <Select the user name>
            -> Variable name: PATH
            -> Value: /usr/bin:/bin:<your personal path>
            -> Add environment variable: Before all Cron jobs for user
Peter VARGA
la source