Bash shell:如何协调可移植配置文件和 GUI 终端启动类型(登录或交互)?

jml*_*ane 5 terminal bash shell gui bashrc

为了“正确”实现我喜欢的 shell 的标准配置bash,以便在多个平台上使用,在处理与他们选择的 shell 启动类型(登录或交互式)不一致的终端时,我遇到了一些困惑)。

Bash 启动文件

从 bash 手册中,我确定了启动文件和它们来源的顺序/案例之间的区别(/etc/profile~/.bash_profile~/.bash_login、 和~/.profile登录 shell,以及~/.bashrc交互式非登录 shell)。该文档建议您将特定于 bash 的登录配置存储~/.bash_profile~/.bashrc. 手册本身甚至建议添加if [ -f ~/.bashrc ]; then source ~/.bashrc; fi~/.bash_profile文件中,以便登录 shell 继承您的交互式 shell 设置。

从我在手册和各种在线论坛/文档中读到的内容来看,将非 bash 特定的登录配置抽象为明智之举,~/.profile因为其他 shell 可以获取此文件。对于除了 bash 之外还可能使用 Bourne shell 的人来说,这可能是一个边缘情况(这在我的情况下不太可能),但这似乎是一个好习惯。

到目前为止,这一切看起来都非常简单和合乎逻辑,尤其是在各种 shell 启动类型之间的区别很明显的环境中:在命令行是主要界面的系统或终端上,登录 shell 是您的主要会话 shell ,交互式 shell 是在该会话中启动的后续 shell,而您的非交互式 shell 是运行脚本的 shell。

真正令人困惑的是,当您的 shell 从已通过系统身份验证的 GUI 环境中的终端启动时,登录 shell 的构成是什么?在我看来,Mac OSX Terminal.app 中的默认行为是让在每个窗口中运行的 shell 启动登录 shell,而在 xterm 中,每个新窗口都是一个交互式 shell。


我可能会看到一个不存在的问题,但请考虑以下问题:终端情况表明,如果我在~/.bashrc以 bash 启动的终端上工作,我将绝大多数配置放入以避免丢失功能交互式外壳。由于不熟悉 bash 何时可能作为交互式 shell 产生的复杂性,我不得不依赖这样的声明,即~/.bashrc像这样滥用最终会导致登录 shell 配置放错位置的问题,不利于正常的 shell 功能。不难想象,当您忽略手册的建议并不当使用配置文件时,可能会出现问题。

由于您不能真正依赖 using~/.bashrc作为您的包罗万象,似乎您可能需要根据您使用的终端对您的~/.bash_profile~/.bashrc文件进行不同的处理。这似乎会导致很多麻烦,并且与首先拥有这些不同启动文件的目的背道而驰!

所以最后我的问题如下:

  • 当前的 Bash shell 用户如何解决 GUI 终端在启动登录和交互式 shell 之间不一致的问题?
  • 您如何创建一组用于跨平台(和跨终端)使用的 bash 启动文件,而不会遇到问题?

感谢您的帮助和建议。

Gil*_*il' 5

误用 shell 启动文件导致的最常见问题是,如果您在 中定义环境变量,.bashrc.profile不是在不是从终端中的 shell 而是从 GUI 菜单启动的应用程序中定义它们。

从定义环境变量.bashrc通常不是一个好主意,但这主要是因为它通常没有用,因为变量应该在登录时已经设置。如果您(或应用程序)故意更改程序中变量(例如PATH)的值,并且您从该程序启动 shell 并期望设置保持不变,则在实践中可能会导致问题。

您可以通过定义一个“哨兵”值来避免环境变量被重置的问题,如果设置了哨兵值,则不定义任何内容:

if [ -z "$JMLANE_PROFILE_READ" ]; then
  export ...
  export JMLANE_PROFILE_READ=1
fi
Run Code Online (Sandbox Code Playgroud)

终端启动登录 shell 引起的另一个问题是,有些事情应该在您登录时只执行一次,例如启动密码代理(例如ssh-agent),或启动会话(例如startx在某些情况下运行)。哨兵变量避免了这些问题。

终端内的外壳始终是交互式的。只要您.bashrc.bash_profileshell 交互时获取源代码,您就无需担心终端启动登录 shell。

bash 启动文件处理的另一个问题是.bashrc由 rshd 或 sshd 调用的非交互式 shell 读取。例如,当您这样做时rsync somefile host.example.com:,如果您的登录 shellhost.example.com是 bash,您可以使用.bashrc那里将路径设置为 include rsync。您可以判断自己处于这种情况,因为它.bashrc是从非交互式 shell 读取的。

## .bashrc
if [[ $- != *i* ]]; then
  # either .bashrc was executed explicitly or this is a noninteractive rsh/ssh session
fi
Run Code Online (Sandbox Code Playgroud)