在我的拱安装,/etc/bash.bashrc
以及/etc/skel/.bashrc
包含这些行:
# If not running interactively, don't do anything
[[ $- != *i* ]] && return
Run Code Online (Sandbox Code Playgroud)
在 Debian 上,/etc/bash.bashrc
有:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Run Code Online (Sandbox Code Playgroud)
并且/etc/skel/.bashrc
:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Run Code Online (Sandbox Code Playgroud)
man bash
然而,根据,非交互式 shell 甚至不读取这些文件:
When bash is started non-interactively, to run a shell script, for
example, it looks for the variable BASH_ENV in the environment, expands
its value if it appears there, and uses the expanded value as the name
of a file to read and execute. Bash behaves as if the following com?
mand were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the file?
name.
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,*.bashrc
文件将仅在BASH_ENV
设置为指向它们时才会被读取。这是不可能偶然发生的事情,只有在有人相应地明确设置变量时才会发生。
这似乎打破了.bashrc
通过设置自动获取用户脚本的可能性BASH_ENV
,这可能会派上用场。鉴于 bash 在非交互式运行时永远不会读取这些文件,除非明确告知这样做,为什么默认*bashrc
文件不允许它?
Ant*_*gan 84
这是我几周前要在这里发布的问题。像terdon一样,我知道 a.bashrc
仅用于交互式 Bash shell,因此不需要.bashrc
检查它是否在交互式 shell 中运行。令人困惑的是,我使用的所有发行版(Ubuntu、RHEL 和 Cygwin)都有某种类型的检查(测试$-
或$PS1
)以确保当前的 shell 是交互式的。我不喜欢Cargo cult 编程,所以我开始在我的.bashrc
.
在研究了这个问题后,我发现远程 shell的处理方式不同。虽然非交互式 Bash shell 通常不会~/.bashrc
在启动时运行命令,但当 shell 被远程 shell daemon 调用时会产生一种特殊情况:
Bash 尝试确定它何时在其标准输入连接到网络连接的情况下运行,如由远程 shell 守护程序(通常
rshd
)或安全 shell 守护程序执行时sshd
。如果 Bash 确定它正在以这种方式运行,它会从 ~/.bashrc 读取并执行命令,如果该文件存在且可读。如果作为sh
. 该--norc
选项可用于禁止此行为,并且该--rcfile
选项可用于强制读取另一个文件,但既rshd
不会也不sshd
通常使用这些选项调用 shell 或允许指定它们。
在 remote 的开头插入以下内容.bashrc
。(如果.bashrc
来自.profile
或.bash_profile
,请在测试时暂时禁用此功能):
echo bashrc
fun()
{
echo functions work
}
Run Code Online (Sandbox Code Playgroud)
在本地运行以下命令:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
Run Code Online (Sandbox Code Playgroud)
i
in$-
表示外壳是非交互式的。-
在$0
表示该外壳不是登录shell。.bashrc
也可以运行在远程定义的 Shell 函数:
$ ssh remote_host fun
bashrc
functions work
Run Code Online (Sandbox Code Playgroud)
我注意到,~/.bashrc
在只有当命令被指定为参数来源ssh
。这是有道理的:whenssh
用于启动常规登录 shell,.profile
或.bash_profile
运行(并且.bashrc
仅在由这些文件之一明确执行时才获取)。
.bashrc
在运行(非交互式)远程命令时,我可以看到的主要好处是可以运行 shell 函数。但是,典型命令中的大多数命令.bashrc
仅与交互式 shell 相关,例如,除非 shell 是交互式的,否则不会扩展别名。
当rsh
或ssh
用于启动交互式登录 shell 或使用非交互式 shell 运行命令时,这通常不是问题。但是,对于诸如,和使用远程 shell传输数据的程序来说,这可能是一个问题。rcp
scp
sftp
事实证明,在使用该scp
命令时,远程用户的默认 shell(如 Bash)是隐式启动的。有没有在手册页没有这方面的记载-仅一提的是scp
使用ssh
它的数据传输。这导致如果.bashrc
包含任何打印到标准输出的命令,文件传输将失败,例如,
scp 失败而没有错误。
另请参阅 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
。shell 启动文件之所以重要,是因为它
sshd
在代表用户启动任何程序时使用用户的 shell (使用例如 /bin/sh -c "command")。这是 Unix 的传统,并且具有以下优点:
- 用户的常用设置(命令别名、环境变量、umask 等)在运行远程命令时生效。
- 将帐户的 shell 设置为 /bin/false 以禁用它的常见做法将阻止所有者运行任何命令,如果身份验证仍然出于某种原因意外成功。
对于那些对 SCP 如何工作的细节感兴趣的人,我在 SCP 协议的工作原理中找到了有趣的信息,其中包括在远程端使用健谈的 shell 配置文件运行 scp 的详细信息?:
例如,如果您将其添加到远程系统上的 shell 配置文件中,就会发生这种情况:
回声“”
为什么它只是挂起?这来自于
scp
在源模式下如何等待第一个协议消息的确认。如果它不是二进制 0,它期望它是远程问题的通知,并等待更多字符形成错误消息,直到新行到达。由于您没有在第一行之后打印另一行新行,因此您的本地人scp
只是停留在一个循环中,在read(2)
. 同时,在远程端处理 shell 配置文件后,scp
在接收器模式下启动,它也阻塞在 上read(2)
,等待表示数据传输开始的二进制零。
典型.bashrc
中的大多数语句仅对交互式 shell 有用 - 在使用rsh
或运行远程命令时无效ssh
。在大多数情况下,不需要设置 shell 变量、别名和定义函数——如果使用或等程序传输文件,将任何文本打印到标准输出都是有害的。在验证当前 shell 是非交互式之后退出是.scp
sftp
.bashrc
Mik*_*kel 16
手册页忽略了非交互式远程 shell 的bash
来源.bashrc
,如
ssh hostname command
Run Code Online (Sandbox Code Playgroud)
http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1010
COMMAND EXECUTE BASHRC
--------------------------------
bash -c foo NO
bash foo NO
foo NO
rsh machine ls YES (for rsh, which calls 'bash -c')
rsh machine foo YES (for shell started by rsh) NO (for foo!)
echo ls | bash NO
login NO
bash YES
Run Code Online (Sandbox Code Playgroud)
http://git.savannah.gnu.org/cgit/bash.git/tree/shell.c#n1050
/* If we were run by sshd or we think we were run by rshd, execute
~/.bashrc if we are a top-level shell. */
if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
{
maybe_execute_file (SYS_BASHRC, 1);
maybe_execute_file (bashrc_file, 1);
Run Code Online (Sandbox Code Playgroud)
按照惯例,.bashrc
是用户存储外壳自定义配置的地方。
这些自定义配置可以是环境变量、别名、花哨的提示。对于非交互式 shell,那些缺少的东西毫无意义。此外,可以在许多上下文中调用非交互式 shell,您不确定这些环境变量是否会导致误报情况,甚至安全漏洞。
一个最接近的例子是一个别名,如:
alias cp='cp -i'
Run Code Online (Sandbox Code Playgroud)
然后它永远挂起你的非交互式 shell。
所以检查在顶部执行.bashrc
以确保我们不会遇到麻烦。
因为 shell 可以被称为非交互式登录shell,所以明确阻止采购*bashrc
是没有意义的。
当炮弹被称为非交互式登录shell,它源/etc/profile
,那么其中的第一个发现~/.bash_profile
,~/.bash_login
和~/.profile
:
当 bash 作为交互式登录 shell或作为带有 --login 选项的非交互式 shell调用时,它首先从文件 /etc/profile 读取并执行命令(如果该文件存在)。读取该文件后,它会按顺序查找 ~/.bash_profile、~/.bash_login 和 ~/.profile,然后从第一个存在且可读的命令中读取和执行命令。
没有什么可以阻止这些文件.bashrc
自行采购,因此在内部进行检查.bashrc
更安全并使事情变得简单。