web-dev-qa-db-ja.com

環境変数を新しいsshで開始されたログインセッションに渡す方法は?

現在の環境でいくつかの変数FOOが定義されている(そしてexport- edされている)と仮定します。この環境をE0と呼びます。

ここで、sshを使用して他のUnixシステムにログインします。

% ssh [email protected]

この新しく確立されたセッションの環境をE1と呼びます。

一般にFOOE1で定義されず、例外がある場合は一般にその値は、E0FOOの値とは無関係に設定されます。

sshを介してログインしたときに、変数FOOE1E0にある値に設定されるようにするにはどうすればよいですか(理想的には、export- E1にも含まれています)?

必要に応じて、E0E1の両方にzshを使用しています。

この質問の答えとして、for.example.comで実行されているsshdプロセスの構成を制御できないと仮定します。これは、特に、/etc/ssh/sshd_configfor.example.comなどを変更する必要があるソリューションを除外します。

また、FOOの値が一定ではないと仮定します。あるログインセッションから別のログインセッションに変わります。特に、FOOFOOにまったく設定できない場合があります。その場合、E1への影響がFOO=またはexport FOO=またはunset FOOの影響に類似していても問題ありません。


PDATE:私はこれを試しました

% ssh [email protected] FOO=$FOO env

...そして実際、出力はFOOが指定どおりに設定されていることを示しています。しかし、ログインセッションを開始するときにこの方法を適用する方法はわかりませんでした。具体的には、実行すると

% ssh [email protected] FOO=$FOO

...コマンドは接続を確立せずに戻るだけです(sshFOO=$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

新しい環境と整理する必要のある通常の環境の間には、まだ重要な違いがありますが、これは私が望むものにかなり近いです。

4
kjo

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がべき等であることを確認することで修正することもできます)。