为什么与手动运行相比,SSH远程命令获得的环境变量更少?[关闭]


239

我有一条命令,如果我将ssh切换到机器上并运行它,它将运行正常,但是当我尝试使用远程ssh命令运行该命令时,该命令将失败:

ssh user@IP <command>

使用这两种方法比较“ env”的输出结果将在不同的环境中进行。当我手动登录到计算机并运行env时,与运行时相比,我得到了更多的环境变量:

ssh user@IP "env"

知道为什么吗?


30
为什么这个问题恰好是关闭主题?
jottr 2014年

13
可能是因为它与编程无关。它应该已移至“超级用户”而不是关闭。
Daniel H

8
bash不是脚本语言吗?
Dan Nissenbaum

在Debian 8中,出于某种原因,我不得不在/ etc / passwd中将shell更改为bash。甚至重新配置破折号以使/ bin / sh指向bash也无济于事。
user1050755 '19

Answers:


173

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

       登录外壳是其参数的第一个字符
       零是-,或以--login选项开头的一个。

       交互式外壳是一种无需选择就可以启动的外壳
       参数且不带-c选项的标准输入
       和错误都连接到端子(确定
       通过isatty(3)),或以-i选项开头的一个。PS1是
       如果bash是交互式的,则设置和$-包括i,从而允许
       Shell脚本或启动文件来测试此状态。

       以下段落描述了bash如何执行其
       启动文件。如果任何文件存在但不能
       读取后,bash报告错误。波浪线在文件中扩展
       名称,如下所述,
       扩展部分。

       当bash作为交互式登录shell或作为
       具有--login选项的非交互式外壳,它首先
       从文件/ etc / profile中读取并执行命令,如果
       该文件存在。读取该文件后,它会寻找
       〜/ .bash_profile,〜/ .bash_login和〜/ .profile,
       命令,并从第一个命令读取并执行命令
       存在并且可读。--noprofile选项可能
       在外壳启动时使用以禁止这种行为
       or

       登录外壳退出时,bash读取并执行命令
       从文件〜/ .bash_logout(如果存在)中。

       当不是登录外壳程序的交互式外壳程序是
       开始,bash从〜/ .bashrc读取并执行命令,
       如果该文件存在。这可以通过使用
       --norc选项。--rcfile文件选项将强制bash
       从文件而不是从中读取和执行命令
       〜/ .bashrc。

       当bash非交互启动时,运行一个shell
       脚本,例如,它在以下位置查找变量BASH_ENV
       环境,如果它在那里出现,则扩大其价值,
       并将扩展值用作要读取的文件的名称
       并执行。Bash的行为就像以下命令
       被执行:
              如果[-n“ $ BASH_ENV”]; 然后 。“ $ BASH_ENV”; 科幻
       但是PATH变量的值不用于搜索
       作为文件名。


7
很好的答案,这正是问题所在,所需的环境变量位于/ etc / bashrc中,该变量不是以非交互方式提供的。将它们移至/ etc / profile可以解决此问题。非常感谢你!
汤姆·费纳

1
这个答案只是部分解决方案。这里有一些更多信息:将不同的环境变量(例如,导出SOURCED_SYSTEM_ETC_BASHRC)添加到获取源文件的各种文件中:/etc/profile、etc/bashrc、~/.profile、~/.bash_profile、~/bashrc。然后在Jenkins输出中查找该唯一变量。就我而言,我将/ etc / bashrc更新为包含“ export SOURCED_SYSTEM_ETC_BASHRC =是”,并且该变量显示在该节点的Jenkins日志中。因此,在我的情况下,要为jenkins从属设置环境变量,它们必须放在/ etc / bashrc中。Jenkins ssh登录源自/ etc / bashrc。
Coder Roadie

更正:我的意思是/etc/bash.bashrc,而不是/ etc / bashrc。
Coder Roadie

37
那是一堵文字墙,我认为值得强调一下,这ssh user@host "bash --login -c 'command arg1 ...'"将使远程Shell设置登录环境。您引用的部分确实提到了,--login但是很容易忽略这一点。
codebeard

谢谢你的这篇文章,我曾经ssh <ssh options> <IP> bash --login my_script.sh在远程计算机上运行脚本,可以享受待遇,使我能够成功使用本地环境变量,例如JAVA_HOME
markc

117

运行命令之前如何获取概要文件?

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

您可能会发现最好的改变,要~/.bash_profile~/.bashrc或什么的。

(如此处(linuxquestions.org)


1
遇到此问题,此解决方案效果很好。
Sam152

10
必须总是输入额外的代码只是为了获取环境是荒谬的!
2013年

4
一个很少重复键入这类事情的人,通常是在脚本中,因此,只要能起作用,“多余的代码”有多大就无关紧要了:tm:
Ian Vaughan

1
如果我同时提供/ etc / profile和〜/ .bash_profile(以使用户添加到路径),那么它可以工作,但是很难看。必须有一种更简单的方法来告诉命令(在我的示例中为xterm)使用“交互式”登录并以远程计算机上的用户特定路径结尾?
杰西

ssh $ 1“源〜/ .bashrc;〜/ temp_unix.sh”在这里temp_unix.sh导出了MANI_HOME =“ mani deepak”,但它不起作用。
mani deepak 2014年

90

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

vi ~/.ssh/environment

其格式为:

VAR1=VALUE1
VAR2=VALUE2

另外,请检查sshd配置以了解PermitUserEnvironment=yes选项。


1
完美!+100,如果我可以的话:)
Dexter 2012年

VisualGDB失败,并显示错误“ bash:gcc:找不到命令”,此解决方案对此进行了纠正。
KalenGi

太棒了。希望我早在几年前就知道了。
重力

这是完美的答案!
Jirapong 2015年

1
@ pg2455,虽然您并非总是能够在服务器上配置sshd(或不想全部启用它),但仍可以编辑用户环境
dpedro

63

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

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

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

8
另外,您可以将所有“非交互式”代码放在该行的上方。
machineghost 2012年

美丽,为我节省了很多时间:)谢谢
Lance Pollard

谢谢。只需添加带有return语句的文件即可在处找到/etc/bash.bashrc
2014年

无论如何,有没有绕过服务器中的此代码而不更改它?
Yoni

我花了很多时间试图理解为什么我的脚本不起作用。谁认为将这些行放在.bashrc中是个好主意?
Sharcoux '18年

4

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

在先前的响应之一中,建议使用〜/ .bashr_profile等...。我并没有花很多时间,但是,问题是如果您在目标系统上使用与登录源系统上的shell SSH不同的用户,这似乎会导致源系统用户用于〜的名称。


完善!解决问题的不错的单线解决方案。
corpico

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.