为啥 SSH 远程命令在手动运行时获得的环境变量更少? [关闭]

Posted

技术标签:

【中文标题】为啥 SSH 远程命令在手动运行时获得的环境变量更少? [关闭]【英文标题】:Why does an SSH remote command get fewer environment variables then when run manually? [closed]为什么 SSH 远程命令在手动运行时获得的环境变量更少? [关闭] 【发布时间】:2010-09-17 23:43:58 【问题描述】:

如果我 ssh 到一台机器并运行它,我有一个运行良好的命令,但是当我尝试使用远程 ssh 命令运行它时失败:

ssh user@IP <command>

在不同环境中使用两种方法比较“env”的输出。当我手动登录机器并运行 env 时,我得到的环境变量比运行时多得多:

ssh user@IP "env"

知道为什么吗?

【问题讨论】:

为什么这个问题作为题外话被关闭了? 可能是因为它与编程无关。它应该被移到超级用户而不是关闭。 bash 不是脚本语言吗? 在 Debian 8 中,出于某种原因,我不得不将 shell 更改为 /etc/passwd 中的 bash。甚至重新配置 dash 以让 /bin/sh 指向 bash 也无济于事。 【参考方案1】:

运行远程 ssh 命令时不加载 Shell 环境。您可以编辑 ssh 环境文件:

vi ~/.ssh/environment

它的格式是:

VAR1=VALUE1
VAR2=VALUE2

另外,检查sshd 配置中的PermitUserEnvironment=yes 选项。

【讨论】:

完美!如果可以的话 +100 :) VisualGDB 失败并出现错误“bash: gcc: command not found”,这个解决方案纠正了这个问题。 太棒了。真希望我几年前就知道这一点。 这是完美的答案! @pg2455 虽然您并不总是能够在您的服务器上配置 sshd(或者不想为所有人启用它),但您仍然可以编辑您的用户环境【参考方案2】:

我有类似的问题,但最后我发现 ~/.bashrc 是我所需要的。

但是,在 Ubuntu 中,我不得不注释停止处理 ~/.bashrc 的行:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return

【讨论】:

或者,您可以将所有“非交互式”代码放在该行之上。 漂亮,为我节省了很多时间 :) 谢谢 谢谢。只需添加带有 return 语句的文件即可在 /etc/bash.bashrc 找到。 有没有办法绕过服务器中的这段代码而不改变它? 我花了很多时间试图理解为什么我的脚本不起作用。谁认为将这些行放在 .bashrc 中是个好主意???【参考方案3】:

只需在 ~/.bashrc 中检查非交互式 shell 的上方导出所需的环境变量即可。

【讨论】:

【参考方案4】:

在运行命令之前获取配置文件怎么样?

ssh user@host "source /etc/profile; /path/script.sh"

您可能会发现最好将其更改为 ~/.bash_profile~/.bashrc 或其他任何名称。

(作为here (linuxquestions.org))

【讨论】:

有这个问题,这个解决方案效果很好。 必须总是输入额外的代码来获取环境是荒谬的! 很少有人重复输入这类东西,通常它会在脚本中,因此,有多少“额外代码”并不重要,只要它有效:tm:跨度> 如果我同时获取 /etc/profile 和 ~/.bash_profile (以使用户添加到路径)它可以工作,但它很难看。必须有一种更简单的方法来告诉命令(在我的情况下为 xterm)使用“交互式”登录并最终在远程计算机上获得完整的用户特定路径? ssh $1 "source ~/.bashrc; ~/temp_unix.sh" 这里 temp_unix.sh 有 export MANI_HOME="mani deepak" 但它不工作。【参考方案5】:

我发现解决此问题的一个简单方法是添加 源 /etc/profile 到我试图在目标系统上运行的 script.sh 文件的顶部。 在此处的系统上,这会导致将 script.sh 所需的环境变量配置为好像从登录 shell 运行一样。

在之前的回复之一中,有人建议使用 ~/.bashr_profile 等...。 我没有花太多时间在这上面,但是问题是,如果你 ssh 到目标系统上的另一个用户,而不是你登录的源系统上的 shell,在我看来,这会导致源系统用户用于 ~ 的名称。

【讨论】:

完美!很好的单线解决方案。【参考方案6】:

有不同类型的贝壳。 SSH 命令执行外壳是非交互式外壳,而您的普通外壳是登录外壳或交互式外壳。描述如下,来自 man bash:

登录 shell 是其参数的第一个字符 零是 -,或者以 --login 选项开头。 交互式外壳是在没有非选项的情况下启动的 参数并且没有标准输入的 -c 选项 和错误都连接到终端(如确定 通过 isatty(3)),或者以 -i 选项开头。 PS1 是 如果 bash 是交互式的,则 set 和 $- 包括 i,允许 shell 脚本或启动文件来测试这个状态。 以下段落描述了 bash 如何执行其 启动文件。如果任何文件存在但不能 读,bash 报错。波浪号在文件中展开 名称如下所述的波浪号扩展中的 扩展部分。 当 bash 作为交互式登录 shell 调用时,或者作为 带有 --login 选项的非交互式 shell,它首先 从文件 /etc/profile 读取并执行命令,如果 该文件存在。读取该文件后,它会寻找 ~/.bash_profile、~/.bash_login 和 ~/.profile,其中 命令,并从第一个命令中读取并执行命令 存在并且可读。 --noprofile 选项可以 在 shell 启动时使用以抑制此行为 约尔。 当登录 shell 退出时,bash 读取并执行命令 从文件 ~/.bash_logout,如果它存在。 当不是登录 shell 的交互式 shell 是 启动时,bash 从 ~/.bashrc 读取并执行命令, 如果该文件存在。这可以通过使用 --norc 选项。 --rcfile 文件选项将强制 bash 从文件中读取和执行命令,而不是 〜/ .bashrc。 当 bash 以非交互方式启动时,运行 shell 例如,它在脚本中查找变量 BASH_ENV 环境,如果它出现在那里,它的价值就会扩大, 并使用扩展值作为要读取的文件名 并执行。 Bash 的行为就像以下命令一样 被处决: 如果 [ -n "$BASH_ENV" ];然后 。 "$BASH_ENV";菲 但 PATH 变量的值不用于搜索 为文件名。

【讨论】:

很好的答案,这正是问题所在,所需的环境变量位于 /etc/bashrc 中,它不是以非交互模式获取的。将它们移动到 /etc/profile 解决了这个问题。非常感谢! 这个答案只是部分解决方案。以下是更多信息:将不同的环境变量(例如,导出 SOURCED_SYSTEM_ETC_BASHRC)添加到获取源的各种文件中:/etc/profile、etc/bashrc、~/.profile、~/.bash_profile、~/bashrc。然后在 Jenkins 输出中查找该唯一变量。就我而言,我更新了 /etc/bashrc 以包含“export SOURCED_SYSTEM_ETC_BASHRC=yes”,并且该变量出现在节点的 Jenkins 日志中。所以在我的例子中,要为詹金斯奴隶设置环境变量,他们必须进入 /etc/bashrc. Jenkins ssh login only 来源 /etc/bashrc. 更正:我的意思是 /etc/bash.bashrc,而不是 /etc/bashrc。 那是一大堆文字,我认为值得强调的是ssh user@host "bash --login -c 'command arg1 ...'" 将使远程shell 设置登录环境。您引用的部分确实提到了--login,但很容易忽略这一点。 感谢您的这篇文章,我使用ssh &lt;ssh options&gt; &lt;IP&gt; bash --login my_script.sh 在远程机器上运行脚本,工作得很好,使我能够成功使用本地环境变量,例如JAVA_HOME

以上是关于为啥 SSH 远程命令在手动运行时获得的环境变量更少? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

从 Jenkins 管道运行脚本时,如何通过 ssh 在远程 AIX 机器中加载环境变量?

Linux-两种ssh远程执行命令方式加载环境变量区别

在远程 ssh 命令中传递变量

解决SSH远程执行命令找不到环境变量的问题

SSH连接时发送/设置环境变量

ssh远程连接服务器执行命令