ssh远程命令的$ PATH为什么与交互式shell的$ PATH不同?


20

我有一个用户未对任何点文件中的$ PATH进行任何修改:这正是系统默认设置。从登录shell:

$ ssh example.com
user@example.com:~$ cat /tmp/hello.hs
#!/bin/bash

echo "$SHELL"
echo "$PATH"

user@example.com:~$ /tmp/hello.hs
/bin/bash
/usr/local/bin:/usr/bin:/bin

完全符合中的规定/etc/profile。我觉得这很意外:

$ ssh example.com '/tmp/hello.sh'
/bin/bash       
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games

就像我说的,有一个在$ PATH的任何修改~/.bashrc,也不在/etc/bash.bashrc。无~/.ssh/environment任。该ssh(1)声明环境变量PATH

设置为默认PATH,如编译ssh时所指定。

但是来自StackOverflow的该线程和此邮件列表文章建议我只需修改/ etc / profile,shell启动文件之一等,就应该能够影响给定命令的$ PATH。

这里发生了什么?

Answers:


16

ssh(1)手册页上:“如果指定了命令,那么它将在远程主机而不是登录Shell上执行。”

因此,简而言之,当您实际登录到计算机时,bash作为登录外壳启动并加载适当的文件,当您远程连接并发出命令时,它会代替bash运行,这意味着这些文件不会加载。您可以su -l -c在ssh的命令部分中使用或类似方法解决它。

在某些情况下,我也看到过-t有关ssh工作(分配tty)的争论。

编辑1
我认为您找到的PATH信息是,默认路径(除非我们覆盖它)是编译到sshd中的路径。我确保我的/ etc / profile,/ etc / bash *,本地点文件等中没有任何PATH信息,然后我登录并仍然具有PATH。我在sshd中搜索了此文件,并在其中找到了它。因此,其联机帮助页的内容如下:

ahnberg@remote$ strings /usr/sbin/sshd | grep -i x11 | grep bin
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games

然后,我将文件添加PATH=$PATH:/my/test.bashrc远程文件的顶部,然后再次检查:

ahnberg@local$ ssh ahnberg@remote "env | grep PATH"
PATH=/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/my/test

所以我绝对可以影响它,默认的PATH是编译到sshd中的那个。:)


嗯,我认为“在远程主机上执行”一词的含义远不止于此。我之前想念的更有趣的地方是同一手册页的“环境”部分:“ PATH设置为编译ssh时指定的默认PATH”。除此之外,表明我应该能够影响命令的PATH。
troutwine 2012年

关键是它不是登录shell,因此它不会以与登录shell相同的方式运行/提供/包含启动文件,因此,我建议您尝试一下。放东西.bashrc也许也可以,但是如果PATH很重要,总的来说我会解决它。或者,如果您需要运行ssh的“命令”方式,为什么不只指定完整路径名呢?:)
Mattias Ahnberg

我已经稍微修改了我的帖子。现在,有一个登录外壳,一个非登录外壳及其交互/非交互变体。SSH命令以非交互式非登录形式在用户的外壳程序中调用。该bash(1)INVOCATION表明,没有启动文件都以这种方式阅读,但我不能找到文档如何 SSH是调用外壳。这似乎与上面的链接源相反,除非其他人具有我没有的/ etc / ssh / sshrc启动文件源。(当然,有一些解决方法,但重点是要确切地了解Debian SSHD默认情况下如何处理路径。)
troutwine 2012年

如果我在/etc/profile远程箱上修改PATH 中的路径更新,那么会ssh user@remotebox 'env'向我显示更新后的PATH。如果我添加export PATH=$PATH:/my/testpath到.bashrc ,也会发生同样的事情(但在检查交互式shell之前,在我的文件中位于该文件的顶部(-z "$PS1")。)
Mattias Ahnberg 2012年

更新了我的测试/发现。
Mattias Ahnberg

3

我能够通过运行以下命令使ssh使用远程路径运行命令:

ssh dist@d6 "bash --login -c 'env'"

这里的env可以替换为您想要的任何命令。

我有授权密钥,因此不需要密码即可运行命令或ssh。


3

我想出了另一种方法来解决此问题。我个人的喜好是创建新的配置文件,而不是更改现有的文件。这样,我可以更轻松地从默认配置中确定更改。

以下是内容/etc/profile.d/ssh_login.sh

#!/bin/sh
if [ "$SSH_CONNECTION" ]; then
    echo "User '$USER' logged in from '${SSH_CONNECTION%% *}'"
    . /etc/environment
fi

使用dropbear代替openssh-server(这也应该与openssh一起使用),当我远程登录时,会自动设置SSH_CONNECTION变量。我创建了一个新的外壳配置文件配置,以检测SSH登录,在屏幕上显示一些信息,最重要的是,从中加载全局环境设置/etc/environment以替换已编译的值。请注意,这只会影响交互式SSH Shell,而不会影响远程命令执行。

另外,如果您使用openssh并始终希望加载全局环境,则无论它是否是交互式shell,都可以~/.ssh/像这样放置符号链接:

ln -s /etc/environment ~/.ssh/environment

然后,您需要启用中的PermitUserEnvironment选项/etc/sshd/sshd_config。不过,仅对受信任的用户执行此操作,因为这可以使他们使用LD_PRELOAD之类的机制在某些配置中绕过访问限制。请参阅man sshd_config以获取更多信息,特别是如何使用Match块将选项限制到特定用户/组。


0

如果要加载配置文件路径,请尝试:

#!/bin/bash -i

在脚本的顶部。这样,当运行脚本时,shell处于交互模式。

当bash作为交互式登录shell或具有--login选项的非交互式shell被调用时,它首先从文件/ etc / profile中读取并执行命令(如果该文件存在)。读取该文件后,它将按该顺序查找〜/ .bash_profile,〜/ .bash_login和〜/ .profile,并从存在的且可读的第一个命令中读取并执行命令。启动外壳程序时,可以使用--noprofile选项禁止此行为。

http://linux.die.net/man/1/bash

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.