Comment transmettre des variables d'environnement à une nouvelle session de connection initiée par ssh?

Supposons qu'une variable FOO soit définie (et export ) dans l'environnement actuel. Permettez-moi d'appeler cet environnement E0 .

Maintenant, je me connecte à un autre système Unix en utilisant ssh .

 % ssh [email protected] 

Permettez-moi d'appeler l'environnement de cette nouvelle session E1 .

En général , FOO ne sera pas défini dans E1 , et, dans les cas exceptionnels où il est, sa valeur sera généralement définie indépendamment de la valeur de FOO dans E0 .

Comment puis-je arranger les choses pour que la variable FOO se FOO via ssh , soit positionnée dans E1 à la valeur de E0 (et idéalement export dans E1 )?

Au cas où cela count, j'utilise zsh pour E0 et E1 .

Pour la réponse à cette question, supposons que je n'ai aucun contrôle sur la configuration du process sshd qui s'exécute sur for.example.com . Cela exclut en particulier toute solution nécessitant la modification de /etc/ssh/sshd_config , ou similaire, sur for.example.com .

En outre, supposons que la valeur de FOO n'est pas constante; il va changer d'une session de connection à l'autre. En particulier, FOO ne peut pas être placé dans FOO du tout, auquel cas il est correct si l'effet sur E1 est analogue à FOO= ou export FOO= ou unset FOO .


MISE À JOUR: J'ai essayé ça

 % ssh [email protected] FOO=$FOO env 

… et en effet, la sortie montre que FOO est défini comme spécifié. Mais je n'ai pas compris comment appliquer cette idée lors du lancement d'une session de connection. Plus précisément, si je cours

 % ssh [email protected] FOO=$FOO 

… la command revient juste sans établir de connection (je suppose que ssh interprète FOO=$FOO comme la "command" à exécuter sur l'hôte distant). D'un autre côté, après avoir couru ceci

 % ssh [email protected] FOO=$FOO zsh 

… Je ne vois jamais l'invite du shell depuis l'hôte distant; la command est juste là. (Je reçois cependant une invite de mot de passe de ssh juste avant cela). La même chose se produit pour les autres variantes de la dernière command, comme

 % ssh [email protected] FOO=$FOO /path/to/zsh % ssh [email protected] FOO=$FOO env zsh % ssh [email protected] env FOO=$FOO zsh % ssh [email protected] env FOO=$FOO zsh -l % ssh [email protected] 'env FOO=$FOO zsh' 

UPDATE2: En fait, ce qui semblait être "suspendu" s'avère être que l'invite n'est pas visible. Je peux encore exécuter des commands. En outre, la séquence des files d'initialisation zsh qui sont exécutés lors de la connection est différente de la normale, et (peut-être pas étonnamment) l'environnement est sensiblement différent de la normale (et non sortingvialement, au-delà de FOO ).

UPDATE3: Avec l'aide de dave_alcarin et meuh, j'ai trouvé que ça se rapprochait de ce que je suis:

 % ssh -t [email protected] env FOO=$FOO zsh -l -s 

Il y a encore des différences non sortingviales entre le nouvel environnement et le normal que j'ai besoin de régler, mais c'est assez proche de ce que je veux.

SSH a une fonction permettant de transmettre les variables d'environnement du client au server, mais OpenSSH le désactive dans la configuration du server par défaut. Il y a une exception: TERM , qui occupe une place spéciale dans le protocole; mais la communication d'informations via TERM est gênante car il faut être sûr que le client va le décoder.

Néanless, certains servers sont configurés pour laisser passer certaines variables d'environnement. Par exemple, Debian configure le server SSH pour autoriser toutes les variables dont le nom commence par LC_ . Habituellement, ce sont des variables locales, mais vous pouvez mettre ce que vous voulez.

Si le server n'est pas configuré pour autoriser n'importe quelle variable, vous pouvez les passer dans le cadre de la command, mais il y a quelques rides. Le problème que vous rencontrez est que si vous transmettez une command à ssh , aucun terminal n'est créé par défaut sur le server. Donc, ssh [email protected] FOO=$FOO zsh exécute en fait un shell, mais ce shell est connecté à un pipe, pas à un terminal, il n'affiche donc pas de command line ou d'édition de command line. Néanless, vous pouvez taper des commands – essayez de taper ls Entrée et exit Entrée ou Ctrl + D pour quitter. La solution est de dire explicitement à SSH d'ouvrir un terminal, avec l'option -t .

 ssh -t [email protected] FOO=$FOO zsh 

En fonction de votre shell de connection, vous souhaiterez peut-être exécuter

 ssh -t [email protected] FOO=$FOO exec zsh 

pour éviter d'avoir un process shell supplémentaire qui est le parent de ce zsh invoqué explicitement.

Le deuxième problème que vous n'avez pas encore rencontré est la citation. Le protocole SSH transmet une string qui est exécutée par le shell distant. Ici, vous passez la string composée de FOO= , suivie de la valeur de FOO , suivie d'un espace et exec zsh . Ainsi, la valeur de FOO est interprétée comme un bit de code source shell, non comme une string à stocker dans la variable FOO . Cela fait une différence si la valeur contient des caractères qui ont une signification particulière dans la syntaxe du shell. Vous devez append un niveau supplémentaire de cotation. En supposant que votre shell local est zsh, vous pouvez utiliser l'indicateur d'extension de paramètre q :

 ssh -t [email protected] FOO=${(q)FOO} exec zsh 

Une autre différence avec l'étui droit est que vous exécutez d'abord un shell de connection sur le côté distant, puis le remplacez par un shell non-connection. Comme la string commence par un shell de connection (ce qui ne peut pas être évité), votre .zprofile ou .zprofile est exécuté; Cependant, l'instance interactive de zsh n'est pas un shell de connection, ce qui pourrait faire une différence selon le contenu de vos files de points. La meilleure solution pour cela est probablement d'éviter de faire des choses fragiles dans vos files de points. Vous pouvez exécuter zsh -l , mais il exécute un second shell de connection, ce qui est susceptible de faire plus de différence (bien que vous puissiez le résoudre en .zprofile que votre .zprofile ou .zprofile est idempotent).