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

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

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

Bash 启动文件

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

从我在手册和各种在线论坛/文档中读到的内容来看,将非 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以避免在以交互式 shell 启动 bash 的终端上工作时丢失功能。由于不熟悉 bash 何时可能作为交互式 shell 生成的复杂性,我不得不依靠声明这种滥用~/.bashrc最终会导致问题,登录 shell 配置放错位置会损害正常的 shell 功能。不难想象,当您忽略手册的建议并不当使用配置文件时可能会出现问题。

由于您不能真正依赖使用~/.bashrc作为您的万能工具,因此您可能需要根据您使用的终端以不同的方式处理~/.bash_profile~/.bashrc文件。这似乎会导致很多麻烦,并且与拥有这些不同的启动文件的目的背道而驰!

最后我的问题如下:

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

谢谢您的帮助和建议。

答案1

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

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

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

if [ -z "$JMLANE_PROFILE_READ" ]; then
  export ...
  export JMLANE_PROFILE_READ=1
fi

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

终端内的 shell 始终是交互式的。只要您在shell 处于交互式时.bashrc从源获取信息.bash_profile,就无需担心终端会启动登录 shell。

bash 启动文件处理的另一个缺点是.bashrc被 rshd 或 sshd 调用的非交互式 shell 读取。例如,当您执行 时rsync somefile host.example.com:,如果您的登录 shellhost.example.com是 bash,您可以使用.bashrc来设置要包含 的路径rsync。您可以判断您处于这种情况,因为.bashrc是从非交互式 shell 读取的。

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

相关内容