Pourquoi une commande à distance SSH obtient-elle moins de variables d'environnement que lorsqu'elle est exécutée manuellement? [fermé]

239

J'ai une commande qui fonctionne correctement si je ssh sur une machine et l'exécute, mais échoue lorsque j'essaie de l'exécuter à l'aide d'une commande ssh distante comme:

ssh user@IP <command>

La comparaison de la sortie de "env" en utilisant les deux méthodes se résume dans différents environnements. Lorsque je me connecte manuellement à la machine et que j'exécute env, j'obtiens beaucoup plus de variables d'environnement que lorsque j'exécute:

ssh user@IP "env"

Une idée pourquoi?

Tom Feiner
la source
30
Pourquoi cette question est-elle fermée comme hors sujet?
jottr
13
Probablement parce que ce n'est pas lié à la programmation. Il aurait dû être déplacé vers Super User au lieu d'être fermé.
Daniel H
8
bashn'est pas un langage de script?
Dan Nissenbaum
Dans Debian 8, j'ai dû changer le shell en bash dans / etc / passwd pour une raison quelconque. Même la reconfiguration du tiret pour laisser / bin / sh pointer vers bash n'a pas aidé.
user1050755

Réponses:

173

Il existe différents types d'obus. Le shell d'exécution de commande SSH est un shell non interactif, tandis que votre shell normal est soit un shell de connexion, soit un shell interactif. La description suit, de man bash:

       Un shell de connexion est celui dont le premier caractère d'argument
       zéro est un -, ou un a commencé avec l'option --login.

       Un shell interactif est un shell démarré sans option
       et sans l'option -c dont l'entrée standard
       et l'erreur sont tous deux connectés aux bornes (comme déterminé
       par isatty (3)), ou l'un a commencé avec l'option -i. PS1 est
       set et $ - inclut i si bash est interactif, permettant une
       script shell ou un fichier de démarrage pour tester cet état.

       Les paragraphes suivants décrivent comment bash exécute son
       fichiers de démarrage. Si l'un des fichiers existe mais ne peut pas être
       lu, bash signale une erreur. Les tildes sont développés dans le fichier
       noms comme décrit ci-dessous sous Tilde Expansion dans le
       Section EXPANSION.

       Lorsque bash est invoqué en tant que shell de connexion interactif, ou en tant que
       un shell non interactif avec l'option --login, il commence par
       lit et exécute les commandes du fichier / etc / profile, si
       ce fichier existe. Après avoir lu ce fichier, il recherche
       ~ / .bash_profile, ~ / .bash_login et ~ / .profile, dans ce
       ordre, et lit et exécute les commandes du premier
       qui existe et qui est lisible. L'option --noprofile peut
       être utilisé lorsque le shell est démarré pour inhiber ce comportement
       ior.

       Lorsqu'un shell de connexion se ferme, bash lit et exécute des commandes
       à partir du fichier ~ / .bash_logout, s'il existe.

       Lorsqu'un shell interactif qui n'est pas un shell de connexion est
       démarré, bash lit et exécute les commandes de ~ / .bashrc,
       si ce fichier existe. Cela peut être inhibé en utilisant le
       --norc option. L'option de fichier --rcfile forcera bash
       pour lire et exécuter des commandes à partir d'un fichier au lieu de
       ~ / .bashrc.

       Lorsque bash est démarré de manière non interactive, pour exécuter un shell
       par exemple, il recherche la variable BASH_ENV dans
       l'environnement, augmente sa valeur s'il 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
       ont été exécutés:
              if [-n "$ BASH_ENV"]; puis . "$ BASH_ENV"; Fi
       mais la valeur de la variable PATH n'est pas utilisée pour rechercher
       pour le nom de fichier.

Vinko Vrsalovic
la source
7
Excellente réponse, c'était exactement le problème, les variables d'environnement nécessaires résidaient dans / etc / bashrc, qui n'est pas fourni en mode non interactif. Les déplacer vers / etc / profile a résolu le problème. Merci beaucoup!
Tom Feiner
1
Cette réponse n'est que partielle. Voici quelques informations supplémentaires: ajoutez une variable d'environnement différente (par exemple, exportez SOURCED_SYSTEM_ETC_BASHRC) aux différents fichiers qui proviennent: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Recherchez ensuite cette variable unique dans la sortie Jenkins. Dans mon cas, j'ai mis à jour / etc / bashrc pour contenir «export SOURCED_SYSTEM_ETC_BASHRC = yes», et cette variable est apparue dans le journal Jenkins pour le nœud. Donc dans mon cas, pour définir les variables d'environnement pour les esclaves jenkins, ils doivent aller dans / etc / bashrc. La connexion Jenkins ssh provient uniquement de / etc / bashrc.
Coder Roadie
Correction: je voulais dire /etc/bash.bashrc, pas / etc / bashrc.
Coder Roadie
37
C'est tout un mur de texte, je pense qu'il vaut la peine de souligner que ssh user@host "bash --login -c 'command arg1 ...'"le shell distant configurera l'environnement de connexion. La section que vous avez citée mentionne, --loginmais il serait facile de l'oublier.
codebeard
Merci pour ce message, j'avais l'habitude ssh <ssh options> <IP> bash --login my_script.shd'exécuter un script sur la machine distante, de travailler un régal et de m'avoir permis d'utiliser avec succès des vars env locaux commeJAVA_HOME
markc
117

Que diriez-vous de trouver le profil avant d'exécuter la commande?

ssh user@host "source /etc/profile; /path/script.sh"

Vous trouverez peut - être qu'il valait mieux changer cela à ~/.bash_profile, ~/.bashrcou peu importe.

(Comme ici (linuxquestions.org) )

Ian Vaughan
la source
1
Eu ce problème, cette solution a très bien fonctionné.
Sam152
10
Devoir toujours taper du code supplémentaire juste pour générer l'environnement est ridicule!
Michael
4
On tape rarement à plusieurs reprises ce genre de choses, normalement ce serait dans un script, et en tant que tel, peu importe la quantité de "code supplémentaire" qu'il y a, tant qu'il fonctionne: tm:
Ian Vaughan
1
Si je source à la fois / etc / profile et ~ / .bash_profile (pour obtenir les ajouts des utilisateurs au chemin) cela fonctionne, mais c'est moche. Il doit y avoir un moyen plus simple de dire à la commande (dans mon cas xterm) d'utiliser la connexion "interactive" et de se retrouver avec le chemin complet spécifique à l'utilisateur sur la machine distante?
Jess
ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Ici temp_unix.sh a exporté MANI_HOME = "mani deepak" mais cela ne fonctionne pas.
mani deepak
90

L'environnement Shell ne se charge pas lors de l'exécution de la commande ssh distante. Vous pouvez modifier le fichier d'environnement ssh:

vi ~/.ssh/environment

Son format est:

VAR1=VALUE1
VAR2=VALUE2

Vérifiez également la sshdconfiguration pour l' PermitUserEnvironment=yesoption.

dpedro
la source
1
la perfection! +100 si je pouvais :)
Dexter
VisualGDB échouait avec l'erreur "bash: gcc: command not found" et cette solution a corrigé cela.
KalenGi
fantastique. j'aurais aimé savoir cela il y a des années.
gravitation
C'est la réponse parfaite!
Jirapong
1
@ pg2455 alors que vous n'êtes pas toujours en mesure de configurer sshd sur votre serveur (ou que vous ne voulez pas l'activer pour tous), vous pouvez toujours modifier votre environnement utilisateur
dpedro
63

J'ai eu un problème similaire, mais à la fin j'ai découvert que ~ / .bashrc était tout ce dont j'avais besoin.

Cependant, dans Ubuntu, j'ai dû commenter la ligne qui arrête le traitement de ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
la source
8
Alternativement, vous pouvez simplement mettre tout votre code "non interactif" au-dessus de cette ligne.
machineghost
belle, m'a fait gagner beaucoup de temps :) merci
Lance Pollard
Merci. Il suffit d'ajouter que le fichier avec l'instruction de retour peut être trouvé à /etc/bash.bashrc.
adarshr
Est-il possible de contourner ce code sur le serveur sans le modifier?
Yoni
J'ai passé tellement de temps à essayer de comprendre pourquoi mon script ne fonctionnait pas. Qui a pensé que c'était une bonne idée de mettre ces lignes dans le .bashrc ???
Sharcoux
4

J'ai trouvé une solution facile à ce problème: ajouter le fichier source / etc / profile en haut du fichier script.sh que j'essayais d'exécuter sur le système cible. Sur les systèmes ici, cela a entraîné la configuration des variables d'environnement nécessaires à script.sh comme si elles s'exécutaient à partir d'un shell de connexion.

Dans l'une des réponses précédentes, il a été suggéré d'utiliser ~ / .bashr_profile etc ... Je n'y ai pas passé beaucoup de temps, mais le problème est que si vous utilisez un utilisateur différent sur le système cible que le shell du système source à partir duquel vous vous connectez, il me semble que cela provoque l'utilisateur du système source. nom à utiliser pour le ~.

Mandrin
la source
Parfait! Belle solution en une ligne au problème.
corpico
3

Exportez simplement les variables d'environnement que vous voulez au-dessus de la recherche d'un shell non interactif dans ~ / .bashrc.

Michael MacDonald
la source