我想在远程机器上运行一个脚本。简单的解决方案是这样的:
ssh remote1 some-script
这个方法一直有效,直到远程脚本不想连接到另一个remote2
需要交互式身份验证的远程机器(),就像这个(在这种情况下remote2
只能通过以下方式访问):remote1
ssh remote1 "ssh remote2 some-script"
解决该问题的方法是使用-t
ssh 选项。
ssh -t remote1 "ssh remote2 some-script"
这有效,但如果我使用它,我会遇到问题(some-script
可能会执行进一步的 ssh 命令):
ssh -t remote1 some-script
我发现有些环境变量没有设置,而这些变量是在我不使用该-t
选项时设置的。这些环境变量是在脚本中设置的/etc/profile.d
。我猜想如果使用该选项,这些脚本由于某种原因不会运行-t
,但如果我不使用它,这些脚本就会运行。
这是什么原因?有什么办法可以解决这个问题吗?我正在使用 SUSE Linux(版本 10)。
编辑:我做了一些额外的研究。我将一些输出行放到了以下位置:
- 在一个文件中
/etc/profile.d
- (
~/.bash_profile
文件之前不存在) - (
~/.bashrc
文件之前不存在)
然后我检查了几种情况下我得到的输出以及输出顺序(我检查的环境变量是$PATH
):
ssh remote1
:profile.d
,.bashrc
,.bash_profile
。$PATH
好的。ssh -t remote1
:profile.d
,.bashrc
,.bash_profile
。$PATH
好的。ssh remote1 echo '$PATH'
:仅此而已.bashrc
。$PATH
好的。ssh -t remote1 echo '$PATH'
:无脚本输出。NOK$PATH
。
现在我真的不明白发生了什么。如果我运行一个交互式 shell,一切似乎都运行良好(尽管我发现~/.bashrc
在 之前包含很奇怪~/.bash_profile
)。如果我启动一个没有 的非交互式 shell -t
,配置文件脚本似乎不会运行,但环境变量已设置。如果我用 启动非交互式 shell -t
,则配置文件脚本不会运行,环境变量也不会设置。有人对此有解释吗?
答案1
我没有找到问题的原因。也许它特定于平台(SLES 10 或我使用的变体)。我找到了一种解决方法:
ssh -t remote1 "/bin/bash --login -c some-script"
这将强制运行配置文件脚本的登录 shell。
答案2
所有问题的答案都在 bash 手册页的“INVOCATION”部分中:
当 bash 作为交互式登录 shell 或使用 --login 选项作为非交互式 shell 调用时,它首先从文件 /etc/profile 中读取并执行命令(如果该文件存在)。读取该文件后,它会按顺序查找 ~/.bash_profile、~/.bash_login 和 ~/.profile,然后从第一个存在且可读的文件中读取并执行命令。启动 shell 时可以使用 --noprofile 选项来禁止此行为。
当登录 shell 退出时,bash 会从文件 ~/.bash_logout 读取并执行命令(如果存在)。
当启动非登录 shell 的交互式 shell 时,如果 ~/.bashrc 文件存在,bash 将从该文件中读取并执行命令。可以使用 --norc 选项禁止此操作。--rcfile 文件选项将强制 bash 从文件而不是 ~/.bashrc 中读取并执行命令。
正如您所见,交互式 shell 仅提供来源.bashrc
,并且通常.bash_profile
从那里获取来源,这解释了您所看到的顺序。
很多时候,这些文件还具有仅为交互式 shell 解析某些部分([[ $- == *i* ]]
)的条件,这可以解释为什么某些部分对于非交互式 shell 来说可能缺失。
答案3
和...之间的不同
ssh remote1 echo '$PATH'
和
ssh -t remote1 echo '$PATH'
bash 手册页中也有解释:
Bash 尝试确定何时将其标准输入连接到网络连接来运行,例如由远程 shell 守护程序(通常是
rshd
)或安全 shell 守护程序执行时。如果 bash 确定它以这种方式运行,它将从[我假设应该读取] 和sshd
读取并执行命令(如果这些文件存在且可读)。~/.bashrc
/etc/bash.bashrc
~/.bashrc
在第一个例子中,bash
的标准输入连接到网络连接,因此它运行~/.bashrc
。在第二个例子中,它的标准输入来自伪终端,因此它不运行。