如何将环境变量传递给新的 ssh 启动的登录会话?

如何将环境变量传递给新的 ssh 启动的登录会话?

假设在当前环境中FOO定义(并-ed)某个变量。export让我称这种环境为环境E0

现在,我使用ssh.

% ssh [email protected]

我把这个新建立的会话的环境称为一下E1

一般来说FOO不会在 中定义E1,并且在特殊情况下,一般来说FOO其值的设置将独立于in的值E0

我如何安排事情,以便在登录 via 时ssh,将变量FOO设置E1为它所具有的值E0(并且,理想情况下,也export设置为 -ed )?E1

如果重要的话,我zsh同时使用E0E1

sshd对于这个问题的答案,假设我对 上运行的进程的配置没有任何控制权for.example.com。这尤其排除了任何需要修改/etc/ssh/sshd_config等的解决方案for.example.com

另外,假设 的值FOO不是恒定的;它将从一个登录会话更改为另一个登录会话。特别FOO是 可能根本不设置FOO,在这种情况下,如果 的效果E1类似于FOO=export FOO=的效果就可以了unset FOO


更新:我试过这个

% ssh [email protected] FOO=$FOO env

...事实上,输出显示FOO已按指定设置。但我还没有弄清楚如何在启动登录会话时应用这个想法。具体来说,如果我跑

% ssh [email protected] FOO=$FOO

...命令只是返回而不建立连接(我认为这ssh解释FOO=$FOO为在远程主机上运行的“命令”)。另一方面,在我运行这个之后

% ssh [email protected] FOO=$FOO zsh

...我从未看到来自远程主机的 shell 提示符;命令就挂在那里。 (但是,我确实在此之前收到了密码提示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'

更新2:实际上,看似“挂起”的东西,原来是提示不可见。我仍然可以运行命令。此外,登录时运行的 zsh 初始化文件的顺序与正常情况不同,并且(也许并不奇怪)环境是实质上(而且重要的是,IOW 高于并超越FOO)与正常情况不同。

更新3:在 dave_alcarin 和 meuh 的帮助下,我发现这非常接近我所追求的:

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

新环境和正常环境之间仍然存在一些重要的差异,我需要解决,但这非常接近我想要的。

答案1

SSH 具有将环境变量从客户端传递到服务器的功能,但 OpenSSH 在默认服务器配置中禁用了该功能。有一个例外:TERM,它在协议中占有特殊的位置;但是通过 通信信息TERM很尴尬,因为您必须确保客户端能够对其进行解码。

然而,某些服务器被配置为允许某些环境变量通过。例如,Debian 将 SSH 服务器配置为允许所有名称以LC_.通常这些是区域设置变量,但您可以放置​​任何您喜欢的变量。

如果服务器未配置为允许任何变量,您可以将它们作为命令的一部分传递,但有一些问题。您遇到的问题是,如果您将命令传递给ssh,则默认情况下不会在服务器上创建终端。事实上,它运行一个 shell,但该 shell 连接到管道,而不是终端,因此它不显示提示或支持命令行版本。尽管如此,您可以键入命令 - 尝试键入、 和或+退出。解决方案是使用选项明确告诉 SSH 打开终端。ssh [email protected] FOO=$FOO zshls Enterexit EnterCtrlD-t

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

根据您的登录 shell 的不同,您可能需要运行

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

以避免出现额外的 shell 进程,该进程是显式调用的zsh.

您还没有遇到的第二个问题是引用。 SSH 协议传输由远程 shell 执行的字符串。在这里,您传递的字符串由FOO=、 的值FOO、空格和组成exec zsh。因此, 的值FOO被解释为一段 shell 源代码,而不是存储在FOO变量中的字符串。如果该值包含在 shell 语法中具有特殊含义的字符,则会产生影响。您需要添加额外的引用级别。假设您的本地 shell 是 zsh,您可以使用q参数扩展标志:

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

与直接情况的另一个区别是,您首先在远程端运行登录 shell,然后将其替换为非登录 shell。由于该链以登录 shell 开始(这是不可避免的),因此您的.profileor.zprofile确实会运行;然而,zsh 的交互式实例不是登录 shell,这可能会有所不同,具体取决于点文件的内容。最好的解决方案可能是避免在点文件中做脆弱的事情。您可以运行zsh -l,但这会运行第二个登录 shell,这很容易产生更大的差异(尽管您也可以通过确保您的.profile.zprofile是幂等来解决这个问题)。

相关内容