cron ignore les variables définies dans “.bashrc” et “.bash_profile”

49

J'ai défini la variable "SHELL" dans le fichier / etc / crontab:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

De plus, tous mes scripts dans le fichier / etc / crontab sont démarrés sous l'utilisateur "martin". Cependant, /home/martin/.bash_profile (pour le shell de connexion) et /home/martin/.bashrc (pour le shell qui ne se connecte pas) contiennent des variables qui sont ignorées dans le cas d'un travail cron, mais sont utilisées dans le cas où je me connecte à la machine SSH ou ouvrir une nouvelle session bash. Pourquoi cron ignore ces variables? Cron n’exécute-t-il pas simplement "/ usr / local / bin / bash mon-script.sh" avec les autorisations pour l'utilisateur "martin"?

Martin
la source
2
Les utilisateurs d'Ubuntu peuvent faire remarquer que le défaut de Ubuntu .bashrca une ligne qui l'empêche de courir dans des coquilles non interactives.
Joeytwiddle

Réponses:

72

Vous pouvez rechercher le fichier souhaité en haut du script ou au début du travail pour l'utilisateur qui l'exécute. La commande "source" est une commande intégrée. Vous feriez la même chose si vous apportiez des modifications à ces fichiers pour charger les modifications.

* * * * * source /home/user/.bash_profile; <command>

ou

#!/bin/bash
source /home/user/.bash_profile

<commands>
gNU.be
la source
2
Notez que "source" peut ne pas fonctionner si cron n'utilise pas le bashshell. J'ai ajouté une réponse qui peut gérer le cas lorsque le shell est sh.
Jonathan
Correction de l'erreur
Danny Bullis
23

Parce que ce n'est pas un shell interactif. La même chose se produit lorsque vous ouvrez certains terminaux.

Jetez un oeil à cette question: Qu'est-ce que le fichier .bashrc? | Super utilisateur

Et aussi à celui-ci:

Quelle est la différence entre .bashrc, .bash_profile et .environment? | Débordement de pile

Différents scripts se déclenchent selon que la connexion est un shell de connexion (ou non), un shell interactif (ou non) ou les deux.

Si vous voulez faire bashrc vous aurez besoin de faire ce changement:

Lorsque Bash est démarré de manière non interactive, pour exécuter un script shell, par exemple, il recherche la variable BASH_ENV dans l'environnement, étend sa valeur s'il y apparaît, et utilise la valeur développée comme nom de fichier à lire et à exécuter. . Bash se comporte comme si la commande suivante avait été exécutée:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

mais la valeur de la variable PATH n'est pas utilisée pour rechercher le nom du fichier.

Comme indiqué ci-dessus, si un shell non interactif est appelé avec l' --loginoption, Bash tente de lire et d'exécuter des commandes à partir des fichiers de démarrage du shell de connexion.

Source: Fichiers de démarrage Bash | Manuel de référence Bash | gnu.org

Dave C
la source
Donc, si nous définissons BASH_ENV dans Cron, les scripts cron bash le trouveront parce que cron est non interactif et non connecté.
CMCDragonkai
13

Vous ne pourrez peut-être pas vous lancer sourcesi le shshell est utilisé. Cela peut être changé en ajoutant la ligne suivante dans votre crontab:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

Vous pouvez également spécifier l'environnement:

BASH_ENV="/root/.bashrc"
* * * * * <command>

ou vous pouvez utiliser votre section locale /home/user/.bashrcs'il s'agit d'un travail utilisateur (par exemple crontab -e).

Notez que cela .bash_profilepeut remplacer .bashrc, s'il existe.

Crédit: Comment changer de shell cron (sh en bash)?

Jonathan
la source
cela fonctionne également pour les tâches planifiées d'Acquia Cloud, qui sont essentiellement des tâches cron. Vous pouvez faire la même chose, comme par exemple:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno
1

Les .bashrcvérifications effectuées par ce fichier pour détecter les shells interactifs peuvent également interférer avec le sourcing de votre travail cron.

Par exemple, sur Ubuntu 18.04, la valeur .bashrcpar défaut pour un utilisateur commence par ceci:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

et si le sourcing ne fera rien d’utile car il sortira immédiatement.

François Marier
la source
1

Vous pouvez appeler bash avec l' -loption, comme ceci:

* * * * * /bin/bash -l /path/to/script arg1 arg2

L' -loption fait bash un shell de connexion . Ainsi, il lira l'utilisateur .bash_profile. Il ne lira l'utilisateur .bashrcque s'il est explicitement recherché par .bash_profile. En effet, les shells non interactifs ne lisent pas automatiquement .bashrc. Mais vous ne devriez pas avoir besoin .bashrcd’un travail cron car .bashrcc’est utile pour configurer des choses utiles pour un shell interactif .

Variations:

Si bash est sur le PATH, il n'est pas nécessaire de spécifier un chemin absolu:

* * * * * bash -l /path/to/script arg1 arg2

Une optimisation consisterait à remplacer le shell actuel en utilisant exec:

* * * * * exec bash -l /path/to/script arg1 arg2
Robin A. Meade
la source
1

bashagit différemment, que ce soit un shell ou un langage de programmation normal (comme perlou python).

De par sa conception, les paramètres ~/.bash_profile, ~/.bashrcetc. sont pour les utilisateurs à des choses ensemble quand bashjoue le rôle d'un shell (shell de connexion, shell interractive). Pensez à l'environnement que vous avez dans un xterm(shell interactif) ou dans des sshsessions (shell de connexion) ou dans des consoles (shell de connexion).

D'autre part, il bashs'agit également d'un puissant langage de programmation ( pensez à de nombreux scripts pour la gestion de services dans systemd) qui nécessite un style de travail différent. Par exemple, lorsqu'un développeur est en train d'écrire un script système ou un bashprogramme, il / elle ne voudra pas rechercher ~/.bash_profileautomatiquement le nom de l'utilisateur . C'est un programme normal, pas un shell. Un programme normal (y compris les bashprogrammes) hériterait naturellement des paramètres de l'environnement de travail actuel (shell), mais ne les définirait pas.

Si nous écrivons un programme pour cronin bash–it, il se trouve simplement qu’il est écrit bash; en fait, nous pouvons écrire dans pythonou perlou tout autre Progamming Langue- alors nous pouvons avoir une option pour les sources bashd » ~/.bash_profile(lire: réglage du shell de l' utilisateur, qui se trouve être la même langue de votre langage de programmation):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

Cependant, que se passe-t-il si cet utilisateur ne l’utilise pas en bashtant que shell? Il / elle peut utiliser zsh, ksh, fish, etc. Ainsi, cette pratique ne fonctionnerait pas vraiment lorsque le programme d' écriture pour un usage public.

Donc, vous pouvez rechercher ~/.bash_profilesi cela vous convient. Mais ici, il ne s'agit pas de savoir si nous sommes en mesure de créer un fichier, mais de savoir comment les choses devraient fonctionner dans le système: le concept de conception . En bref: nous devrions considérer bashque quelque chose a 2 rôles: shell et langage de programmation . Alors tout sera beaucoup plus facile à comprendre.

Bach Lien
la source
0

J'ai eu le même problème lors de l'exécution d'une application de nœud à partir de cron qui utilise NVM.

par exemple: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Si cela ne fonctionne pas, essayez de définir une variable de chemin dans crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "
Shyam Jos
la source
-1

Ma façon de gérer cela était la suivante:

1) Mettre mes variables dans (la fin de) ~/.profile:

myVarInDotProfile="someValue"

2) Créer un script Bash pour mes tâches (quotidiennes) cron ( ~/cronDaily.sh) contenant mes commandes ainsi que l’approvisionnement répétitif de ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) planifier l'exécution de mon script à partir de crontab, pour s'exécuter quotidiennement:

0 0 * * * bash ~/cronDaily.sh

Ma variable n'a pas été ignorée et les commandes ont été exécutées avec succès.


Certains pourraient dire qu'un tel sourçage intense ~/.profileest problématique. Dans mon cas particulier, je ne vois pas pourquoi c'est un problème, mais je vous conseillerais de créer un fichier dédié à cela.

En général, il existe peut-être un meilleur moyen de procéder mais c’est ce qui a fonctionné pour moi après beaucoup de souffrances et cela explique le principe selon lequel, à partir de Bash 4.3.46, vous ne pouvez plus créer un fichier crontab.

Arcticooling
la source