web-dev-qa-db-fra.com

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

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 sans journalisation) contiennent certaines variables qui sont ignorées en cas du travail cron, mais sont utilisés dans le cas où je me connecte à la machine via SSH ou ouvre une nouvelle session bash. Pourquoi cron ignore ces variables? Cron n'exécute-t-il pas simplement "/ usr/local/bin/bash my-script.sh" avec les autorisations de l'utilisateur "martin"?

56
Martin

Vous pouvez rechercher le fichier souhaité en haut du script ou au début du travail pour l'utilisateur qui exécute le travail. La commande "source" est 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>
80
gNU.be

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

Jetez un œil à cette question: Qu'est-ce que le fichier .bashrc? | Super User

Et aussi à celui-ci:

Quelle est la différence entre .bashrc, .bash_profile et .environment? | Stack Overflow

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 devrez 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, développe sa valeur si elle y apparaît et utilise la valeur développée comme nom d'un fichier à lire et à exécuter. . Bash se comporte comme si la commande suivante était 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 de fichier.

Comme indiqué ci-dessus, si un shell non interactif est appelé avec le --login, 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

26
Dave C

Vous ne pourrez peut-être pas exécuter source si le shell sh 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 /home/user/.bashrc s'il s'agit d'un travail cron utilisateur (par exemple crontab -e).

Notez que .bash_profile peut remplacer .bashrc, s'il existe.

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

13
Jonathan

Autre élément susceptible d'interférer avec l'approvisionnement de votre .bashrc à partir d'un cronjob est tout contrôle effectué par ce fichier afin de détecter les shells interactifs.

Par exemple, sur Ubuntu 18.04, la valeur par défaut .bashrc 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 donc l'approvisionnement ne fera rien d'utile car il se fermera immédiatement.

2
Francois Marier

Vous pouvez invoquer bash avec le -l option, comme ceci:

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

Le -l l'option fait de bash un login Shell. Ainsi, il lira le .bash_profile. Il ne lira pas le .bashrc sauf si elle est explicitement fournie par .bash_profile. En effet, les shells non interactifs ne lisent pas automatiquement .bashrc. Mais vous ne devriez pas avoir besoin de .bashrc pour un travail cron car .bashrc sert à définir des éléments 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 serait de remplacer le shell actuel en utilisant exec:

* * * * * exec bash -l /path/to/script arg1 arg2
2
Robin A. Meade

bash agit différemment que ce soit un Shell ou un normal langage de programmation (comme Perl ou python).

De par leur conception, les paramètres de ~/.bash_profile, ~/.bashrc, etc. permettent aux utilisateurs de définir les choses lorsque bash joue le rôle d'un shell (shell de connexion, shell interactif). Pensez à l'environnement que vous avez dans un xterm (shell interactif) ou dans des sessions ssh (shell de connexion) ou dans des consoles (shell de connexion).

D'autre part, bash est également un puissant langage de programmation –pensez à de nombreux scripts de gestion des services dans systemd– qui nécessitent un style de travail différent. Par exemple, lorsqu'un développeur écrit un script système ou un programme bash, il/elle n'aimera pas source _ ~/.bash_profile automatiquement. C'est un programme normal, pas un Shell. Un programme normal (y compris les programmes bash) aurait naturellement hérité les paramètres de l'environnement de travail actuel (Shell), mais pas défini eux.

Si nous écrivons un programme pour cron dans bash –il se trouve simplement être écrit dans bash; en fait, nous pouvons l'écrire dans python ou Perl ou tout autre langage de programmation - alors nous pouvons avoir une option pour les sources bash's ~/.bash_profile (lire: paramétrage du shell de l'utilisateur, qui se trouve être le même langage que votre langage de programmation):

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

Cependant, que se passe-t-il si cet utilisateur particulier n'utilise pas bash comme shell? Il/elle peut utiliser zsh, ksh, fish, etc. Ainsi, cette pratique ne fonctionnerait pas vraiment lors de l'écriture d'un programme à usage public.

Vous pouvez donc source ~/.bash_profile si vous pensez que cela fonctionnera. Mais, ici, il ne s'agit pas de savoir si nous sommes en mesure de trouver un fichier, il s'agit de savoir comment les choses devraient fonctionner dans le système: le concept de conception. En bref: nous devrions voir bash comme quelque chose ayant 2 rôles: Shell et langage de programmation. Ensuite, tout sera beaucoup plus facile à comprendre.

1
Bach Lien

J'ai eu le même problème lors de l'exécution d'une application de noeud à 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 la 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 "
0
Shyam Jos