現在の環境でいくつかの変数FOO
が定義されている(そしてexport
- edされている)と仮定します。この環境をE0
と呼びます。
ここで、ssh
を使用して他のUnixシステムにログインします。
% ssh [email protected]
この新しく確立されたセッションの環境をE1
と呼びます。
一般に、FOO
はE1
で定義されず、例外がある場合は一般にその値は、E0
のFOO
の値とは無関係に設定されます。
ssh
を介してログインしたときに、変数FOO
がE1
でE0
にある値に設定されるようにするにはどうすればよいですか(理想的には、export
- E1
にも含まれています)?
必要に応じて、E0
とE1
の両方にzsh
を使用しています。
この質問の答えとして、for.example.com
で実行されているsshd
プロセスの構成を制御できないと仮定します。これは、特に、/etc/ssh/sshd_config
でfor.example.com
などを変更する必要があるソリューションを除外します。
また、FOO
の値が一定ではないと仮定します。あるログインセッションから別のログインセッションに変わります。特に、FOO
はFOO
にまったく設定できない場合があります。その場合、E1
への影響がFOO=
またはexport FOO=
またはunset FOO
の影響に類似していても問題ありません。
PDATE:私はこれを試しました
% ssh [email protected] FOO=$FOO env
...そして実際、出力はFOO
が指定どおりに設定されていることを示しています。しかし、ログインセッションを開始するときにこの方法を適用する方法はわかりませんでした。具体的には、実行すると
% ssh [email protected] FOO=$FOO
...コマンドは接続を確立せずに戻るだけです(ssh
がFOO=$FOO
をリモートホストで実行する「コマンド」として解釈することを理解しています)。一方、これを実行した後
% ssh [email protected] FOO=$FOO zsh
...リモートホストからシェルプロンプトが表示されません。コマンドはそこでハングします。 (ただし、この直前にssh
からパスワードプロンプトを取得します。)最後のコマンドの他のバリアントについても同じことが起こります。
% 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'
PDATE2:実際、「ハング」しているように見えるのは、プロンプトが表示されていないことです。コマンドはまだ実行できます。また、ログイン時に実行されるzsh初期化ファイルのシーケンスは通常とは異なり、(おそらく驚くべきことではありませんが)環境はsubstantiallyです(そして当然のことながら、IOWはFOO
を超えており、通常とは異なります。
PDATE3: dave_alcarinとmeuhの助けを借りて、これが私が求めているものにかなり近いことがわかりました:
% ssh -t [email protected] env FOO=$FOO zsh -l -s
新しい環境と整理する必要のある通常の環境の間には、まだ重要な違いがありますが、これは私が望むものにかなり近いです。
SSHにはクライアントからサーバーに環境変数を渡す機能がありますが、OpenSSHはデフォルトのサーバー構成でそれを無効にします。ただし、例外が1つあります。TERM
は、プロトコルで特別な位置にあります。ただし、TERM
を介した情報の通信は、クライアントが情報をデコードすることを確認する必要があるため、厄介です。
それにもかかわらず、一部のサーバーは一部の環境変数を通過させるように構成されています。たとえば、DebianはSSHサーバーを設定して、名前がLC_
で始まるすべての変数を許可します。通常、これらはロケール変数ですが、好きなように置くことができます。
サーバーが変数を許可するように構成されていない場合は、コマンドの一部としてそれらを渡すことができますが、いくつかのしわがあります。あなたが直面しているしわは、ssh
にコマンドを渡した場合、デフォルトではサーバー上にターミナルが作成されないことです。したがって、ssh [email protected] FOO=$FOO zsh
は実際にはシェルを実行しますが、そのシェルはターミナルではなくパイプに接続されているため、プロンプトは表示されず、コマンドラインエディションもサポートされません。それでも、コマンドを入力できます— ls
と入力してみてください Enter、およびexit
Enter または Ctrl+D 出る。解決策は、-t
オプションを使用して、SSHに端末を開くように明示的に指示することです。
ssh -t [email protected] FOO=$FOO zsh
ログインシェルが何であるかに応じて、実行することができます
ssh -t [email protected] FOO=$FOO exec zsh
明示的に呼び出されたzsh
の親である余分なシェルプロセスを避けるため。
まだ実行していない2番目の問題は引用です。 SSHプロトコルは、リモートシェルによって実行される文字列を送信します。ここでは、FOO=
、_FOO
の値、スペース、exec zsh
の順に構成された文字列を渡しています。したがって、FOO
の値は、FOO
変数に格納する文字列としてではなく、シェルのソースコードの一部として解釈されます。シェル構文で特別な意味を持つ文字が値に含まれている場合、これにより違いが生じます。引用のレベルを追加する必要があります。ローカルシェルがzshであると想定すると、q
パラメータ拡張フラグを使用できます。
ssh -t [email protected] FOO=${(q)FOO} exec zsh
通常のケースとのもう1つの違いは、最初にリモート側でログインシェルを実行してから、それを非ログインシェルに置き換えることです。チェーンはログインシェルで始まるので(これは避けられません)、.profile
または.zprofile
は実行されます。ただし、zshの対話型インスタンスはログインシェルではないため、ドットファイルの内容によっては異なる場合があります。そのための最善の解決策は、おそらくあなたのドットファイルで壊れやすいことをしないことです。 zsh -l
を実行できますが、2番目のログインシェルが実行されます。これにより、さらに違いが生じる傾向があります(ただし、.profile
または.zprofile
がべき等であることを確認することで修正することもできます)。