在任何 sh shell 启动之前,我需要执行一些重要的命令。这是在 SSH 命令 ( ssh host somecommand
) 和其他运行命令的程序中传递 SSH 命令所必需的。
在我的.profile
我有这个:
ihammerhands@wreckcreations:~> cat .profile
#specific environment and startup programs
export PS1="\u@wreckcreations:\w> "
export PYTHONPATH=~/python/lib/python2.4/site-packages
export PATH=$PATH:~/bin:~/python/bin
但是,这失败了:
W:\programming\wreckcreations-site\test-hg>ssh name@host echo $PATH
Enter passphrase for key '/home/Owner/.ssh/id_rsa':
/usr/local/bin:/bin:/usr/bin
注意缺少的 PATH 选项
sh 配置文件的正确名称是什么?注意:我没有 root 访问权限,也不希望将其应用于其他用户。还有其他方法可以做到这一点吗?
编辑:它似乎/bin/sh
链接到bash
,这并不奇怪。令人惊讶的是我的个人资料仍然被忽略。有什么建议么?
答案1
~/.profile
仅由登录 shell 执行。调用 shell 的程序决定该 shell 是否为登录 shell(通过将 a-
作为 shell 调用中第 0 个参数的第一个字符)。当您登录执行特定命令时,它通常不会被执行。
特别是,仅当您未指定命令时,OpenSSH 才会调用登录 shell。因此,如果您确实指定了命令,~/.profile
则不会被读取。
OpenSSH 允许在服务器端设置环境变量。必须在以下位置启用此功能服务器配置,与PermitUserEnvironment
指令。变量可以在文件中设置~/.ssh/environment
。假设您使用公钥身份验证,您还可以在中设置每个密钥变量~/.ssh/authorized_keys
: 添加environment="FOO=bar"
在相关行的开头。
ssh 还支持发送环境变量。在 OpenSSH 中,使用以下SendEnv
指令~/.ssh/config
。但是,必须使用服务器配置中的指令启用特定的环境变量AcceptEnv
,因此这可能不适合您。
我认为只要您使用公钥身份验证,总是有效的一件事(很奇怪)就是(ab)使用文件command=
中的选项authorized_keys
。带选项的键command
仅适用于运行指定的命令;但文件中的命令authorized_keys
运行时环境变量SSH_ORIGINAL_COMMAND
设置为用户指定的命令。如果用户未指定命令并因此需要交互式 shell,则此变量为空。所以你可以使用这样的东西~/.ssh/authorized_keys
(当然,如果你不使用这个密钥进行身份验证,它将不适用):
command=". ~/.profile; if [ -n \"$SSH_ORIGINAL_COMMAND\" ]; then eval \"$SSH_ORIGINAL_COMMAND\"; else exec \"$SHELL\"; fi" ssh-rsa …
另一种可能性是在服务器上编写包装脚本。类似于以下内容~/bin/ssh-wrapper
:
#!/bin/sh
. ~/.profile
exec "${0##*/}" "$@"
然后建立指向该脚本的符号链接rsync
,称为 、 等。在命令行上unison
传递,依此类推以用于其他程序。或者,某些命令允许您指定要远程运行的整个 shell 片段,这允许您使命令独立:例如,对于 rsync,您可以使用.--rsync-path='bin/rsync'
rsync
--rsync-path='. ~/.profile; rsync'
还有另一种途径,具体取决于您的登录 shell 是 bash 还是 zsh。 Bash~/.bashrc
在被 rshd 或 sshd 调用时总是读取,即使它不是交互式的(但如果它被称为 as 则不会sh
)。 Zsh 总是读取~/.zshenv
.
## ~/.bashrc
if [[ $- != *i* ]]; then
# Either .bashrc was sourced explicitly, or this is an rsh/ssh session.
. ~/.profile
fi
## ~/.zshenv
if [[ $(ps -p $PPID -o comm=) = [rs]shd && $- != *l* ]]; then
# Not a login shell, but this is an rsh/ssh session
. ~/.profile
fi
答案2
似乎值得注意的是,您在问题中提到的命令
ssh name@host echo $PATH
几乎永远不会有用。 $PATH 的变量替换由本地 shell 完成,并传递给 ssh,后者在远程系统上执行 echo 以打印路径变量的内容,因为它在本地系统上扩展。下面是我在我的 Mac 和网络上的 Linux 机器之间执行类似操作的示例:
LibMBP:~ will$ echo $PATH
/opt/local/bin:/opt/local/sbin:/Users/will/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
LibMBP:~ will$ ssh warren echo $PATH
will@warren's password:
/opt/local/bin:/opt/local/sbin:/Users/will/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
LibMBP:~ will$ ssh warren 'echo $PATH'
will@warren's password:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
LibMBP:~ will$
请注意我如何需要使用引号来防止本地 shell 扩展变量。
答案3
通常在登录时,bash 会从以下位置读取命令:
〜/ .bash_profile
〜/ .bashrc
来自 bash 手册页:
~/.bash_profile
个人初始化文件,为登录 shell 执行~/.bashrc
每个交互式 shell 的单独启动文件
答案4
(已删除...新用户只能有一个超链接~)
更新
抱歉,我没有看到这是关于非交互式会话,上面的链接不适用于该会话。
当 Bash 以 SH 兼容模式启动时,它会尝试尽可能模仿 sh 历史版本的启动行为,同时也符合 POSIX® 标准。如果是登录 shell,则读取的配置文件是 /etc/profile 和 ~/.profile。
如果它不是登录 shell,则会评估环境变量 ENV,并将生成的文件名作为启动文件的名称。
读取启动文件后,Bash 进入 POSIX(r) 兼容模式(用于运行,而不是启动!)。
Bash 在以下情况下以 sh 兼容模式启动:
- argv[0] 中的基本文件名是 sh (:!: 亲爱的超级聪明的 Linux 用户请注意... /bin/sh 可能链接到 /bin/bash,但这并不意味着它的行为类似于 /bin/bash :!:)
所以问题是,为什么它不执行它,即使你的 shell 是这样启动的。