这个问题是我几周前要在这里发布的。像terdon一样,我知道a .bashrc
仅来自交互式Bash shell,因此无需.bashrc
检查它是否在交互式shell中运行。令人困惑的是,我使用的所有发行版(Ubuntu,RHEL和Cygwin)都进行了某种类型的检查(测试$-
或$PS1
),以确保当前shell是可交互的。我不喜欢崇拜货物的程序,所以我开始着手了解该代码的目的.bashrc
。
Bash对于远程shell有特殊情况
在研究了该问题之后,我发现对远程Shell的处理有所不同。虽然非交互式Bash Shell通常~/.bashrc
在启动时不运行命令,但是当远程远程守护程序调用 Shell时会出现一种特殊情况:
Bash尝试确定其标准输入连接到网络连接时是何时运行,就像通常由远程Shell守护程序rshd
或安全Shell守护程序执行时一样sshd
。如果Bash确定它是以这种方式运行的,则它从〜/ .bashrc读取并执行命令(如果该文件存在并且可读)。如果以调用,它将不会执行此操作sh
。该--norc
选项可用于禁止这种行为,并且该--rcfile
选项可用于强制读取另一个文件,但是既不使用这些选项rshd
也不sshd
通常使用这些选项来调用Shell或允许它们被指定。
例
将以下内容插入到遥控器的开头.bashrc
。(如果.bashrc
来自.profile
或.bash_profile
,则在测试时暂时将其禁用):
echo bashrc
fun()
{
echo functions work
}
在本地运行以下命令:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- No
i
in $-
表示外壳是非交互式的。
- 没有领导
-
在$0
表示该外壳不是登录shell。
远程中定义的Shell函数.bashrc
也可以运行:
$ ssh remote_host fun
bashrc
functions work
我注意到,~/.bashrc
在只有当命令被指定为参数来源ssh
。这是有道理的:when ssh
用于启动常规登录Shell .profile
或.bash_profile
运行(并且.bashrc
仅在其中一个文件明确这样做的情况下才提供source)。
我可以看到.bashrc
运行(非交互式)远程命令时获得源代码的主要好处是可以运行shell函数。但是,典型命令中的大多数命令.bashrc
仅在交互式外壳中才有用,例如,除非外壳是交互式的,否则别名不会扩展。
远程文件传输可能会失败
当使用rsh
或ssh
用于启动交互式登录Shell或使用非交互式Shell运行命令时,通常这不是问题。然而,这可能是个问题了,如程序rcp
,scp
并sftp
使用远程shell传输数据。
事实证明,使用该scp
命令时,隐式启动了远程用户的默认外壳程序(如Bash)。有没有在手册页没有提到这-只提及scp
使用ssh
它的数据传输。这样的结果是,如果.bashrc
包含任何可打印到标准输出的命令,文件传输将失败,例如,
scp失败而没有error。
另请参阅此15年前的相关Red Hat错误报告,当/ etc / bashrc中有一个echo命令(最终以形式关闭WONTFIX
)时,scp中断。
为什么scp
和sftp
失败
SCP(安全副本)和SFTP(安全文件传输协议)具有自己的协议,供本地和远程端交换有关正在传输的文件的信息。来自远端的任何意外文本都(错误地)被解释为协议的一部分,并且传输失败。根据蜗牛书的常见问题解答
经常会发生什么,不过,是有系统无论是陈述或者每个用户的shell启动文件的服务器上(.bashrc
,.profile
,
/etc/csh.cshrc
,.login
,等),由人阅读登录输出文本消息,意(如fortune
,echo "Hi there!"
,等等。)。
如果在tty
标准输入中附加了这样的代码,则仅在交互式登录时才产生输出
。如果未进行此测试,它将在不属于这些文本消息的地方插入这些文本消息:在这种情况下,污染scp2
/ sftp
和之间的协议流sftp-server
。
外壳程序启动文件完全相关的原因是,sshd
在代表用户启动任何程序时
(例如,使用/ bin / sh -c“ command”),都使用了用户外壳程序。这是Unix的传统,具有以下优点:
- 用户的常规设置(命令别名,环境变量,umask等)在运行远程命令时生效。
- 将帐户的外壳程序设置为/ bin / false以禁用它的通常做法是,如果由于某种原因身份验证仍然意外成功,则所有者将无法运行任何命令。
SCP协议详细信息
对于那些对SCP的工作原理感兴趣的人,我在SCP协议的工作原理中发现了有趣的信息,其中包括有关在远端使用健谈的shell配置文件运行scp的详细信息?:
例如,如果将其添加到远程系统的shell配置文件中,则可能发生这种情况:
回声“”
为什么它挂了?这来自于scp
在源模式下如何等待对第一协议消息的确认的方式。如果它不是二进制0,则它期望它是一个远程问题的通知,并等待更多字符形成错误消息,直到新行到达为止。由于您没有在第一行之后再打印另一行,因此您的本地行scp
仅停留在一个循环中,在处被阻止read(2)
。同时,在远程配置了Shell配置文件后,scp
启动了接收器模式,该模式也处于阻塞状态read(2)
,等待二进制零表示数据传输开始。
结论/ TLDR
典型的大多数语句.bashrc
仅对交互式shell有用,而在使用rsh
或运行远程命令时则无效ssh
。在大多数情况下,不需要设置shell变量,别名和定义函数- 如果使用诸如或的程序传输文件,将任何文本打印为标准输出都是有害的。验证当前外壳程序是非交互式后退出是最安全的行为。scp
sftp
.bashrc