假设在当前环境中FOO
定义(并-ed)某个变量。export
让我称这种环境为环境E0
。
现在,我使用ssh
.
% ssh [email protected]
我把这个新建立的会话的环境称为一下E1
。
一般来说,FOO
不会在 中定义E1
,并且在特殊情况下,一般来说FOO
其值的设置将独立于in的值E0
。
我如何安排事情,以便在登录 via 时ssh
,将变量FOO
设置E1
为它所具有的值E0
(并且,理想情况下,也export
设置为 -ed )?E1
如果重要的话,我zsh
同时使用E0
和E1
。
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 zsh
ls
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 开始(这是不可避免的),因此您的.profile
or.zprofile
确实会运行;然而,zsh 的交互式实例不是登录 shell,这可能会有所不同,具体取决于点文件的内容。最好的解决方案可能是避免在点文件中做脆弱的事情。您可以运行zsh -l
,但这会运行第二个登录 shell,这很容易产生更大的差异(尽管您也可以通过确保您的.profile
或.zprofile
是幂等来解决这个问题)。