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).